gpt4 book ai didi

javascript - React.js - 带有 useState Hook 的功能组件不会按预期重新呈现

转载 作者:行者123 更新时间:2023-11-30 06:14:23 24 4
gpt4 key购买 nike

这是一个有点开放性的问题,因为我确定我处理这个问题的方式是不正确的。但我很好奇为什么 React 没有像我期望的那样重新渲染。我怀疑这与 useState Hook 与功能组件配对的行为有关。

代码在这个CodeSandbox链接和代码如下:

function App() {
var foosList = ["foo1", "foo2", "foo3"];

const [selectedFoo, setSelectedFoo] = useState(-1);
const isSelected = i => i === selectedFoo;

return (
<div className="App">
<FoosWrapper>
<TitleSpan>Foos</TitleSpan>
<ListGroup>
{foosList.map((fooItem, i) => (
<ListGroupItem
key={fooItem}
active={isSelected(i)}
onClick={() => setSelectedFoo(i)}
>
{fooItem}
</ListGroupItem>
))}
</ListGroup>
</FoosWrapper>
<BarsWrapper>
<TitleSpan>Bars</TitleSpan>
<Bars foo={foosList[selectedFoo]} />
</BarsWrapper>
</div>
);
}

const Bars = props => {
const [pendingBar, setPendingBar] = useState("");
const [newBars, setNewBars] = useState([]);

const keyPress = e => {
if (e.key === "Enter") {
save(pendingBar);
}
};

const save = bar => {
newBars.push(bar);
setNewBars([...newBars]);
};

return (
<div>
<ListGroup>
<ListGroupItem key={props.foo}>{props.foo}</ListGroupItem>
</ListGroup>
<ListGroup>
{newBars.map(newBar => (
<ListGroupItem key={newBar}>{newBar}</ListGroupItem>
))}
</ListGroup>
<InputGroup>
<Input
placeholder="Add a bar"
onChange={e => setPendingBar(e.target.value)}
onKeyPress={keyPress}
/>
</InputGroup>
</div>
);
};

大体上,有两个逻辑小部件:FoosBarsFoos 在左边,Bars 在右边。我想让用户选择一个“foo”,并在右侧显示一个与所述“foo”相关联的不同条形列表。用户可以向每个相应的“foo”添加新的条。可以认为 foobar 有父关系。

Bars 组件维护着用户添加的柱状图列表。我的期望是 Bars 组件会在选择新的 foo 时重新呈现内部 newBars 集合。但是,无论在左侧选择什么“foo”,该状态都会一直存在并显示。

这看起来很奇怪,但也许我没有以正确的方式思考 React 功能组件和 Hook 。很想了解为什么存在这种行为,另外很想听到更有意义的建议方法。

非常感谢任何见解!

最佳答案

如果你想反射(reflect)层次结构,那么初始化你的酒吧的状态,以便它与你的 foos 的状态同步。现在,您的 Bars 是独立于 App 维护其自身状态的单个组件。以下是我处理这种特殊关系的方式。

function App() {
const foos = useMemo(() => ["foo1", "foo2", "foo3"], []);
const [bars, setBars] = useState(foos.map(() => []));
const [selectedIndex, setSelectedIndex] = useState(0);
const setBar = useCallback(
bar => {
setBars(bars => Object.assign(
[...bars],
{ [selectedIndex]: bar }
));
},
[setBars, selectedIndex]
);
const isSelected = useCallback(
index => index === selectedIndex,
[selectedIndex]
);
const foosList = useMemo(
() => foos.map((foo, index) => (
<ListGroupItem
key={foo}
active={isSelected(index)}
onClick={() => setSelectedIndex(index)}
>
{foo}
</ListGroupItem>
)),
[foos, isSelected, setSelectedIndex]
);

return (
<div className="App">
<FoosWrapper>
<TitleSpan>Foos</TitleSpan>
<ListGroup>{foosList}</ListGroup>
</FoosWrapper>
<BarsWrapper>
<TitleSpan>Bars</TitleSpan>
<Bars
foo={foos[selectedIndex]}
bars={bars[selectedIndex]}
setBars={setBar}
/>
</BarsWrapper>
</div>
);
}

function Bars({ foo, bars, setBars }) {
const [pendingBar, setPendingBar] = useState("");
const barsList = useMemo(
() => bars.map(bar => (
<ListGroupItem key={bar}>{bar}</ListGroupItem>
)),
[bars]
);
const save = useCallback(
bar => { setBars([...bars, bar]); },
[setBars, bars]
);
const change = useCallback(
event => { setPendingBar(event.target.value); },
[setPendingBar]
);
const keyPress = useCallback(
event => { if (event.key === "Enter") save(pendingBar); },
[pendingBar, save]
);

return (
<div>
<ListGroup>
<ListGroupItem key={foo}>{foo}</ListGroupItem>
</ListGroup>
<ListGroup>{barsList}</ListGroup>
<InputGroup>
<Input
placeholder="Add a bar"
onChange={change}
onKeyPress={keyPress}
/>
</InputGroup>
</div>
);
}

Edit foos and bars hierarchy example

我可能对内存 Hook 有点过头了,但这至少应该让您了解可以内存什么以及如何内存各种值。

请记住,第二个参数是依赖项数组,它决定了内存值是重新计算还是从缓存中检索。钩子(Hook)的依赖是通过引用来检查的,很像一个PureComponent

我还选择将 selectedIndex 初始化为 0 以避免解决当没有 时如何处理 Bars 的渲染函数的问题>foo 被选中。我会把它留给你作为练习。

关于javascript - React.js - 带有 useState Hook 的功能组件不会按预期重新呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57079374/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com