Skip to content
This repository has been archived by the owner on Aug 16, 2023. It is now read-only.

Commit

Permalink
fix: getDerivedStateFromProps
Browse files Browse the repository at this point in the history
  • Loading branch information
zeromake committed Apr 2, 2018
1 parent 6c0d967 commit 8847533
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 112 deletions.
4 changes: 2 additions & 2 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "zreact",
"version": "1.4.1",
"version": "1.4.2",
"description": "React like,copy by preact",
"main": "dist/zreact.js",
"module": "dist/zreact.esm.js",
Expand Down Expand Up @@ -34,7 +34,7 @@
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"prepublishOnly": "npm run build:all",
"docs": "rimraf docs && typedoc --exclude src/devtools-base.ts src/devtools-run.ts --out docs src",
"fix": "sed -i 's/const /var /g' dist/*.js *.js"
"fix": "sed -i 's/const /var /g' dist/*.js"
},
"keywords": [
"zreact",
Expand Down
2 changes: 1 addition & 1 deletion src/options.ts
Expand Up @@ -23,7 +23,7 @@ const options: {
/**
* 自定义异步调度方法,会异步执行传入的方法
*/
debounceRendering?: (render: () => void) => void;
debounceRendering?: (render: (...args: any[]) => void) => void;
/**
* vnode实例创建时的钩子
*/
Expand Down
44 changes: 23 additions & 21 deletions src/vdom/component.ts
Expand Up @@ -54,14 +54,21 @@ export function setComponentProps(component: Component<IKeyValue, IKeyValue>, pr
delete props.key;
}
const vdom = findVDom(component);
const getDerivedStateFromProps = component.constructor && (component.constructor as typeof Component).getDerivedStateFromProps;
if (getDerivedStateFromProps) {
const oldState = component._prevState || component.state;
const newState = getDerivedStateFromProps(props, oldState);
if (newState != null) {
component.state = extend({}, oldState, newState);
}
}
if (!vdom || mountAll) {
// 如果没有插入到DOM树或正在被render渲染执行钩子
if (component.componentWillMount) {
console.warn("componentWillMount is deprecated!");
component.componentWillMount();
}
} else {
const getDerivedStateFromProps = component.constructor && (component.constructor as typeof Component).getDerivedStateFromProps;
if (!getDerivedStateFromProps && component.componentWillReceiveProps) {
// 更新的钩子
console.warn("componentWillReceiveProps is deprecated!");
Expand Down Expand Up @@ -115,7 +122,7 @@ export function renderComponent(component: Component<any, any>, opts?: number, m
// 获取组件props
const props = component.props;
// 获取组件state
let state = component.state;
const state = component.state;
// 获取组件context
let context = component.context;
// 获取组件上一次的props没有取当前
Expand Down Expand Up @@ -150,19 +157,10 @@ export function renderComponent(component: Component<any, any>, opts?: number, m
// shouldComponentUpdate钩子把新的props,state,context作为参数传入
// 如果shouldComponentUpdate钩子返回false,跳过下面的dom操作。
skip = true;
} else {
const getDerivedStateFromProps = component.constructor && (component.constructor as typeof Component).getDerivedStateFromProps;
if (getDerivedStateFromProps) {
const oldState = component.state || emptyObject;
const newState = getDerivedStateFromProps.call(null, props, oldState);
if (newState != null) {
state = extend({}, state || oldState, newState);
}
} else if (component.componentWillUpdate) {
// render Component.forceUpdate更新依旧会触发该钩子。
console.warn("componentWillUpdate is deprecated!");
component.componentWillUpdate(props, state, context);
}
} else if (component.componentWillUpdate) {
// render Component.forceUpdate更新依旧会触发该钩子。
console.warn("componentWillUpdate is deprecated!");
component.componentWillUpdate(props, state, context);
}
// 把组件上的props,state,context都设置到新的
component.props = props;
Expand Down Expand Up @@ -463,21 +461,25 @@ export function unmountComponent(component: Component<any, any>) {
// 解除外部对组件实例的索引
setRef(component._ref, null);
}
interface IAsyncJob {
component: Component<IBaseProps, IKeyValue>;
args: any[];
}

let items: Array<Component<IBaseProps, IKeyValue>> = [];
let items: IAsyncJob[] = [];

/**
* 根据Component队列更新dom。
* 可以setState后直接执行这个方法强制同步更新dom
*/
export function rerender() {
let p: Component<IBaseProps, IKeyValue> | undefined;
let p: IAsyncJob | undefined;
const list = items;
items = [];
while (p = list.pop()) {
if (p._dirty) {
if (p.component._dirty) {
// 防止多次render。
renderComponent(p);
renderComponent(p.component, ...p.args);
}
}
}
Expand All @@ -486,11 +488,11 @@ export function rerender() {
* 把Component放入队列中等待更新
* @param component 组件
*/
export function enqueueRender(component: Component<any, any>) {
export function enqueueRender(component: Component<any, any>, ...args: any[]) {
if (!component._dirty) {
// 防止多次render
component._dirty = true;
const len = items.push(component);
const len = items.push({component, args});
if (len === 1) {
// 在第一次时添加一个异步render,保证同步代码执行完只有一个异步render。
const deferFun = options.debounceRendering || defer;
Expand Down
2 changes: 1 addition & 1 deletion src/vdom/diff.ts
Expand Up @@ -125,7 +125,7 @@ function idiff(
vnode: childType,
context: IKeyValue,
mountAll: boolean,
componentRoot?: boolean,
componentRoot: boolean,
): IVDom {
const prevSvgMode = isSvgMode;
let out = vdom && vdom.base;
Expand Down
110 changes: 39 additions & 71 deletions test/react-test.html
Expand Up @@ -5,100 +5,68 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.bootcss.com/react/16.3.0-alpha.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.3.0-alpha.0/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/react/16.4.0-alpha.0911da3/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0-alpha.0911da3/umd/react-dom.development.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const h = React.createElement
const render = ReactDOM.render
const Component = React.Component
const ThemeContext = React.createContext({
background: 'red',
color: 'white'
});
const ContextMap = {
1: { background: 'red', color: 'white' },
2: { background: 'green', color: 'white' }
}
class App extends Component {
class Test extends Component {
// static getDerivedStateFromProps(nextProps, previousState) {
// console.log(nextProps, previousState)
// return null
// }
constructor() {
super()
this.state = {
map: 1
count: 1
}
this.add = this.add.bind(this)
}
select() {
console.log(JSON.stringify(ThemeContext.currentValue), ThemeContext.changedBits)
this.setState({
map: this.state.map === 1 ? 2: 1
}, function() {
console.log(JSON.stringify(ThemeContext.currentValue), ThemeContext.changedBits)
})
UNSAFE_componentWillReceiveProps(nextProps) {
console.log(nextProps)
}
render () {
return (
h("div", null,
h(ThemeContext.Provider, {value: ContextMap[this.state.map === 1 ? 2: 1]},
h(Header, {map: this.state.map})
),
h(ThemeContext.Provider, {value: ContextMap[this.state.map]},
h(Header, {map: this.state.map === 1 ? 2: 1})
),
h("button", {onClick: () => this.select()}, "测试")
)

);
}
}
class Header extends Component {
shouldComponentUpdate() {
return false
add() {
this.setState(function(state){
return {count: state.count + 1}
})
}
render () {
return h(Title, this.props, "Hello React Context API")
render() {
return h(
"div",
null,
h("h2", null, this.props.title),
h("span", null, this.state.count),
h("button", {onClick: this.add}, "add")
)
}
}
class Title extends Component {
constructor(p, c) {
super(p, c)
class App extends Component {
constructor() {
super()
this.state = {
isShow: true,
title: "",
}
this.select = this.select.bind(this)
this.test = this.test.bind(this)
}
select() {
this.setState({
isShow: !this.state.isShow
test() {
this.setState(function(state) {
return {title: state.title === "" ? "props": ""}
})
}
render () {
return [this.state.isShow ? h(ThemeContext.Consumer, {key: 1},
context => h(this.props.map === 1 ? "h1": "h2", {style: {background: context.background, color: context.color}},
this.props.children
)
): null, h("button", {onClick: () => this.select(), key: 2}, "切换")]
// h(ThemeContext.Consumer, null,
// context => h("h2", {style: {background: context.background, color: context.color}},
// this.props.children
// )
// ),
render() {
return h(
"div",
null,
h(Test, {title: this.state.title}),
h("button", {onClick: this.test}, "test")
)
}
}
render(
h(App),
document.getElementById('app')
);
// class App extends React.Component {
// render() {
// return h(React.Fragment, null,
// h("div", {key: "1"}, "测试1"),
// h("div", {key: "2"}, "测试2")
// )
// }
// }
// ReactDOM.render(h(App), document.getElementById("app"))
render(h(App), document.getElementById("app"))
</script>
</body>
</html>
64 changes: 48 additions & 16 deletions test/test.html
Expand Up @@ -16,27 +16,59 @@
var h = zreact.h;
var render = zreact.render;
var Component = zreact.Component;
function Text(props) {
return props.value
class Test extends Component {
static getDerivedStateFromProps(nextProps, previousState) {
console.log(nextProps, previousState)
return null
}
constructor() {
super()
this.state = {
count: 1
}
this.add = this.add.bind(this)
}
// componentWillReceiveProps(nextProps) {
// console.log(nextProps)
// }
add() {
this.setState(function(state){
return {count: state.count + 1}
})
}
render() {
return h(
"div",
null,
h("h2", null, this.props.title),
h("span", null, this.state.count),
h("button", {onClick: this.add}, "add")
)
}
}
function Test1(props) {
return h(Test, props)
}
class App extends Component {
constructor(p, c) {
super(p, c)
constructor() {
super()
this.state = {
1: null,
2: "null2",
3: null
};
title: "",
}
this.test = this.test.bind(this)
}
test() {
this.setState(function(state) {
return {title: state.title === "" ? "props": ""}
})
}
render() {
const TextChild = []
const ButtonChild = []
for (const key in this.state) {
const val = this.state[key]
TextChild.push(h(Text, {value: val, key}))
ButtonChild.push(h("button", {key, "onClick": () => this.setState({[key]: val? null : "null" + key})}, "button"+ key))
}
return h("div", null, h("div", null, TextChild), h("div", null, ButtonChild))
return h(
"div",
null,
h(Test1, {title: this.state.title}),
h("button", {onClick: this.test}, "test")
)
}
}
render(h(App), document.getElementById("app"))
Expand Down

0 comments on commit 8847533

Please sign in to comment.