[React] react组件重复渲染
Opened this issue · 12 comments
david2tdw commented
david2tdw commented
组件本身使用 useState 或 useReducer 更新,引起的 re-render
常规使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>React template</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Counter = () => {
console.log("counter render");
const [count, addCount] = useState(0);
return (
<div>
<div>{count}</div>
<button
onClick={() => {
addCount(count + 1);
}}
>
add
</button>
</div>
);
};
ReactDOM.render(<Counter />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
immutation state
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>immutation state</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Counter = () => {
console.log("counter render");
//我们将上面计数组件中的 state 值改成引用类型, 点击并不会引起 re-render
const [count, addCount] = useState({
num: 0,
time: Date.now(),
});
const handleClick = () => {
count.num++;
count.time = Date.now();
addCount(count);
};
return (
<div>
<div>
{count.num}, {count.time}
</div>
<button onClick={handleClick}>add</button>
</div>
);
};
ReactDOM.render(<Counter />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
强制更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>强制更新</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Counter = () => {
console.log("counter render");
const [, forceUpdate] = useState({});
//我们将上面计数组件中的 state 值改成引用类型
const [count, addCount] = useState({
num: 0,
time: Date.now(),
});
const handleClick = () => {
count.num++;
count.time = Date.now();
addCount(count);
forceUpdate({});
};
return (
<div>
<div>
{count.num}, {count.time}
</div>
<button onClick={handleClick}>add</button>
</div>
);
};
ReactDOM.render(<Counter />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
父组件更新引起子组件的 re-render
常规使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>常规使用</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Hello = ({ name }) => {
console.log("hello render");
return <div>hello {name}</div>;
};
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = () => {
addCount(count + 1);
};
return (
<div>
<Hello name="react" />
<button onClick={handleClick}>add</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
父组件更新引起子组件的 re-render - 优化组件设计
将更新部分抽离成单独组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>将更新部分抽离成单独组件</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Counter = () => {
console.log("counter render");
const [count, addCount] = useState(0);
const handleClick = () => {
addCount(count + 1);
};
return <button onClick={handleClick}>add</button>;
};
const Hello = ({ name }) => {
console.log("hello render");
return <div>hello {name}</div>;
};
const App = () => {
console.log("app render");
return (
<div>
<Hello name="react" />
<Counter />
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
将不需要 re-render 的部分抽离,以插槽形式渲染(children)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>将不需要 re-render 的部分抽离,以插槽形式渲染</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Hello = ({ name }) => {
console.log("hello render");
return <div>hello {name}</div>;
};
const App = ({ children }) => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = () => {
addCount(count + 1);
};
return (
<div>
{children}
<button onClick={handleClick}>add</button>
</div>
);
};
const Main = () => {
return (
<App>
<Hello name="react" />
</App>
);
};
ReactDOM.render(<Main />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
React.memo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>React.memo</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Hello = React.memo(({ name }) => {
console.log("hello render");
return <div>hello {name}</div>;
});
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = () => {
addCount(count + 1);
};
return (
<div>
<Hello name="react" />
<button onClick={handleClick}>add</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
React.memo 引用类的 props, 添加事件处理的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>React.memo 引用类的 props, 添加事件处理的函数</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const Hello = React.memo(({ name, onClick }) => {
console.log("hello render");
return <div onClick={onClick}>hello {name}</div>;
});
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = () => {
console.log("hello click");
};
return (
<div>
<Hello name="react" onClick={handleClick} />
<button
onClick={() => {
addCount(count + 1);
}}
>
add
</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
useCallback
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>useCallback</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useCallback } = React;
const Hello = React.memo(({ name, onClick }) => {
console.log("hello render");
return <div onClick={onClick}>hello {name}</div>;
});
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = useCallback(() => {
console.log("hello click");
}, []);
return (
<div>
<Hello name="react" onClick={handleClick} />
<button
onClick={() => {
addCount(count + 1);
}}
>
add
</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
useCallback use state
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>useCallback use state</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useCallback } = React;
const Hello = React.memo(({ name, onClick }) => {
console.log("hello render");
return <div onClick={onClick}>hello {name}</div>;
});
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = useCallback(() => {
console.log("hello click count" , count);
}, []);
return (
<div>
<Hello name="react" onClick={handleClick} />
<button
onClick={() => {
addCount(count + 1);
}}
>
add
</button>
<div>count is: {count}</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
useCallback use state fix - 会导致闭包问题,子组件重复渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>useCallback use state fix</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useCallback } = React;
const Hello = React.memo(({ name, onClick }) => {
console.log("hello render");
return <div onClick={onClick}>hello {name}</div>;
});
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const handleClick = useCallback(() => {
console.log("hello click count" , count);
}, [count]);
return (
<div>
<Hello name="react" onClick={handleClick} />
<button
onClick={() => {
addCount(count + 1);
}}
>
add
</button>
<div>count is: {count}</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>
david2tdw commented
useRef & useEffect
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>useRef & useEffect</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style></style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useCallback, useRef, useEffect } = React;
const Hello = React.memo(({ name, onClick }) => {
console.log("hello render");
return <div onClick={onClick}>hello {name}</div>;
});
const App = () => {
console.log("app render");
const [count, addCount] = useState(0);
const countRef = useRef(count);
useEffect(() => {
countRef.current = count;
}, [count]);
const handleClick = useCallback(() => {
console.log("hello click count", countRef.current);
}, [countRef]);
return (
<div>
<Hello name="react" onClick={handleClick} />
<button
onClick={() => {
addCount(count + 1);
}}
>
add
</button>
<div>count is: {count}</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>