讨厌 react 的第一天
react的响应性?
最近在学 next, 做一个聊天小网站练手, 大概遇到了这样的问题: 我要流式输出, 单独用一个小卡片作为流式输出的容器, 等输出完成再放回卡片列表中, 因为其它卡片是需要 Markdown 渲染的, 流式输出的话渲染可能会造成性能问题, 节流什么的影响体验.
在流式输出完成后, 我需要把流式输出的 content 加到列表中, 然后清空 content, 这是个 state. 但是出现了一点问题, 加入列表的居然是空的. 并不是 content 清空的问题, 而是 content 就是空的.
react 有响应式吗? 我觉得如有. 并不是 setContent 就立刻更新 content, 而是在下次渲染的时候, content 的值设置成目标值. 在渲染前, 用的都是原来的值. 而且在直接更新 content 的话也是不具有响应式的, 除非这是个对象.
比如看这份代码.
function App() {
let [count, setCount] = useState(0);
const [a, setA] = useState(0);
const countHandler = () => {
count++;
console.log(count);
}
const aHandler = () => {
setA(a + 1);
console.log(a);
}
return (
<>
<button onClick={countHandler}>count is {count}</button>
<button onClick={aHandler}>a is {a}</button>
</>
);
}
没有意外的话点击count按钮会打印出count, 并且一直在加, 但是显示的count为0. 当点击a按钮的时候, 再点击count就会发现count重置了. React并不实时跟踪变量, 并且setState记录相关操作, 在合适的时间点执行相关操作并比对原值和新值, 如果相同则不渲染, 不同就使用新值渲染, 并且useState会返回新值.
可以试试把上面的setA(a+1)
改成setA(a)
, 会发现count没有重置, 这是因为a的原值跟新值相同, 没有触发渲染. 既然没有触发渲染, setState也不会返回新值.
比较有意思的是, 即使没有使用过setState的state也会进行原值与新值的比对. 可以试试下面的代码
function App() {
const [count, setCount] = useState({
value: 0
});
const [a, setA] = useState(0);
const countHandler = () => {
count.value++;
console.log(count.value);
}
const aHandler = () => {
setA(a+1);
console.log(a);
}
return (
<>
<button onClick={countHandler}>count is {count.value}</button>
<button onClick={aHandler}>a is {a}</button>
</>
);
}
随便按几下count按钮, 会发现一直是0, 不过打印出来不是. 然后按一下a按钮, 会发现count按钮的值更新了. 这是因为react在渲染时会比对所有的state, 无论有没有使用过setState. 这里对象是引用类型, 因此我们改动其那部字段会改变它的值, react检测到了于是进行了更新.
大概就是setState如果原值和新值不同, 那么就会触发渲染. 渲染前react会遍历自己的所有state, 比对原值和新值, 如果有的话就之后就会渲染进去.
不太确定的东西
这里的渲染我更倾向于不是浏览器的渲染, 我试着插入几个节点也没有让react更新state. 我更倾向于是jsx函数的重新执行, 当某个jsx函数的state改变时, 重新调用这个函数, 修改某节点的innerHTML, 这里可能还会涉及一些算法, 尽可能小地改动, 比如不直接修改这个组件的根节点而是修改用到state的节点. 我也不太清楚对不对, 只是一种感觉而已.
总之就是很讨厌. 我可能确实不适合写react吧.