React:如何重构它以防止整个重新渲染并将其封装到重要的组件中?
React: How to refactor this to prevent a whole re-render and encapsulate it towards the component that matters?
我正在使用定义 useState
的父组件来管理我想在面板中显示的消息
类似这样的东西(伪代码)
const Com1 = ({message, setMessage}) => {
useEffect(() => {
const fun = async () => {
if (message) {
await wait(4000)
setMessage('')
}
}
const stillMounted = { value: true }
fun(stillMounted)
return () => (stillMounted.value = false)
}, [message])
return <Message>{message}</Message>
}
const Com2 = ({setMessage}) => {
if (condition) setMessage('important message`)
return <></>
}
const Parent = () => {
const [message, setMessage] = useState('')
return (
<>
<Com1 message={message} setMessage={setMessage} />
<Others1 />
<Others2 />
<Com2 setMessage={setMessage} />
</>
)
}
问题是我希望只有 <Com1> -> <Message>
组件被重新绘制,但我确实 <Others>
也被重新绘制
这很不幸,因为如果我在 <input>
元素中写入数字,当它被重新绘制时,我会丢失我的数字,因为它们重置为原始值
我如何构建我的代码来避免这种情况?
Conponent 呈现或重新呈现此组件内的某处,而您没有 post <Others>
源代码。
无法从外部管理,IFAIK。
React 确实有控制重新渲染的工具,如 shouldComponentUpdate
、React.memo
、React.PureComponent
- 所以你可以 select 一个(在 <Others>
).
它确实有效,只要你不想重新渲染的组件是在父组件之外定义的
在这种情况下,此代码和框仅显示问题,因为 <Others>
是在主要组件内部定义的
如果我将这个组件移到外面,它就不会重新渲染
https://codesandbox.io/s/laughing-swartz-ql8j2?fontsize=14&hidenavigation=1&theme=dark
(代码,不是最简单的代码,但在弄清楚发生了什么的同时,我已经尽可能多地复制了我自己的代码)
import React, { useState, useEffect, useRef, forwardRef } from "react";
import styled from "@emotion/styled";
export const wait = ms =>
new Promise((res, rej) => setTimeout(() => res("timed"), ms));
const useCombinedRefs = (...refs) => {
const targetRef = useRef();
useEffect(() => {
refs.forEach(ref => {
if (!ref) return;
if (typeof ref === "function") ref(targetRef.current);
else ref.current = targetRef.current;
});
}, [refs]);
return targetRef;
};
const Com1 = ({ message, setMessage }) => {
useEffect(() => {
const fun = async () => {
if (message) {
await wait(4000);
setMessage("");
}
};
const stillMounted = { value: true };
fun(stillMounted);
return () => (stillMounted.value = false);
}, [message]);
return <Message show={message ? 1 : 0}>{message}</Message>;
};
const Com2 = ({ setMessage }) => {
const test = async () => {
await wait(4000);
setMessage("important message");
};
useEffect(() => {
test();
}, []);
return <></>;
};
export default function App() {
const [message, setMessage] = useState("");
const myRef1 = useRef();
const myRef2 = useRef();
const Others = forwardRef((props, ref) => {
const innerRef = useRef();
const combinedRef = useCombinedRefs(ref, innerRef);
const write = () => (combinedRef.current.value = 3);
return <input ref={combinedRef} onClick={write} />;
});
return (
<>
<Com1 message={message} setMessage={setMessage} />
<Others ref={myRef1} />
<Others ref={myRef2} />
<Com2 setMessage={setMessage} />
</>
);
}
const Message = styled.div`
background: ${props => (props.show ? "#ababab" : "#fff0")};
width: 100%;
border-radius: 8px;
color: #fff;
padding: 10px;
margin: 10px 0px;
transition: background 0.2s ease-in;
min-height: 50px;
`;
我正在使用定义 useState
的父组件来管理我想在面板中显示的消息
类似这样的东西(伪代码)
const Com1 = ({message, setMessage}) => {
useEffect(() => {
const fun = async () => {
if (message) {
await wait(4000)
setMessage('')
}
}
const stillMounted = { value: true }
fun(stillMounted)
return () => (stillMounted.value = false)
}, [message])
return <Message>{message}</Message>
}
const Com2 = ({setMessage}) => {
if (condition) setMessage('important message`)
return <></>
}
const Parent = () => {
const [message, setMessage] = useState('')
return (
<>
<Com1 message={message} setMessage={setMessage} />
<Others1 />
<Others2 />
<Com2 setMessage={setMessage} />
</>
)
}
问题是我希望只有 <Com1> -> <Message>
组件被重新绘制,但我确实 <Others>
也被重新绘制
这很不幸,因为如果我在 <input>
元素中写入数字,当它被重新绘制时,我会丢失我的数字,因为它们重置为原始值
我如何构建我的代码来避免这种情况?
Conponent 呈现或重新呈现此组件内的某处,而您没有 post <Others>
源代码。
无法从外部管理,IFAIK。
React 确实有控制重新渲染的工具,如 shouldComponentUpdate
、React.memo
、React.PureComponent
- 所以你可以 select 一个(在 <Others>
).
它确实有效,只要你不想重新渲染的组件是在父组件之外定义的
在这种情况下,此代码和框仅显示问题,因为 <Others>
是在主要组件内部定义的
如果我将这个组件移到外面,它就不会重新渲染
https://codesandbox.io/s/laughing-swartz-ql8j2?fontsize=14&hidenavigation=1&theme=dark
(代码,不是最简单的代码,但在弄清楚发生了什么的同时,我已经尽可能多地复制了我自己的代码)
import React, { useState, useEffect, useRef, forwardRef } from "react";
import styled from "@emotion/styled";
export const wait = ms =>
new Promise((res, rej) => setTimeout(() => res("timed"), ms));
const useCombinedRefs = (...refs) => {
const targetRef = useRef();
useEffect(() => {
refs.forEach(ref => {
if (!ref) return;
if (typeof ref === "function") ref(targetRef.current);
else ref.current = targetRef.current;
});
}, [refs]);
return targetRef;
};
const Com1 = ({ message, setMessage }) => {
useEffect(() => {
const fun = async () => {
if (message) {
await wait(4000);
setMessage("");
}
};
const stillMounted = { value: true };
fun(stillMounted);
return () => (stillMounted.value = false);
}, [message]);
return <Message show={message ? 1 : 0}>{message}</Message>;
};
const Com2 = ({ setMessage }) => {
const test = async () => {
await wait(4000);
setMessage("important message");
};
useEffect(() => {
test();
}, []);
return <></>;
};
export default function App() {
const [message, setMessage] = useState("");
const myRef1 = useRef();
const myRef2 = useRef();
const Others = forwardRef((props, ref) => {
const innerRef = useRef();
const combinedRef = useCombinedRefs(ref, innerRef);
const write = () => (combinedRef.current.value = 3);
return <input ref={combinedRef} onClick={write} />;
});
return (
<>
<Com1 message={message} setMessage={setMessage} />
<Others ref={myRef1} />
<Others ref={myRef2} />
<Com2 setMessage={setMessage} />
</>
);
}
const Message = styled.div`
background: ${props => (props.show ? "#ababab" : "#fff0")};
width: 100%;
border-radius: 8px;
color: #fff;
padding: 10px;
margin: 10px 0px;
transition: background 0.2s ease-in;
min-height: 50px;
`;