[英]How do I update the state of a child component?
所以我在我的 React App.js 中有兩個按鈕,單擊時我希望我的當前狀態(列表)根據我按下的按鈕(按日期排序或按投票排序)更改為降序。 我的 articles.js 有顯示文章列表的代碼。 但是我很難顯示在單擊父組件 App.js 上找到的按鈕標簽后排序的列表。
import React, { useState } from 'react';
function Articles({articles}) {
const [list, setList] = useState(articles)
return (
<div className="card w-50 mx-auto">
<table>
<thead>
<tr>
<th>Title</th>
<th>Upvotes</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{list.map((a, i) =>
<tr data-testid="article" key={i}>
<td data-testid="article-title">{a.title}</td>
<td data-testid="article-upvotes">{a.upvotes}</td>
<td data-testid="article-date">{a.date}</td>
</tr>
)}
</tbody>
</table>
</div>
);
}
export default Articles;
import React from 'react';
import './App.css';
import 'h8k-components';
import Articles from './components/Articles';
const title = "Sorting Articles";
function App({articles}) {
//set article to state then pass
const handleUpvotes = () => {
articles.sort((a, b) => a.upvotes - b.upvotes).reverse()
console.log(articles)
}
const handleDates = () => {
return
}
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<div className="layout-row align-items-center justify-content-center my-20 navigation">
<label className="form-hint mb-0 text-uppercase font-weight-light">Sort By</label>
<button data-testid="most-upvoted-link" className="small" onClick={handleUpvotes}>Most Upvoted</button>
<button data-testid="most-recent-link" className="small" onClick={handleDates}>Most Recent</button>
</div>
<Articles articles={articles}/>
</div>
);
}
export default App;
useState
應該在App
中
const [list, setList] = useState(articles)
//set article to state then pass
const handleUpvotes = () => {
articles.sort((a, b) => a.upvotes - b.upvotes).reverse()
setList(articles)
}
您應該使用 Effect Hook ( https://reactjs.org/docs/hooks-effect.html )。
useEffect(() => {
// articles was changed
}, [articles])
您面臨的問題是對 React 反應性 model 的誤解,現在讓我們看看這一行
articles.sort((a, b) => a.upvotes - b.upvotes).reverse()
在這里,您已成功更新數組,但請考慮一下。 如果 React 在組件內的變量更新時更新 UI,那將是無效和有問題的。
因此,為了通知 React 發生了什么變化並且它需要更新 UI,每當您更改變量並且需要更新 UI 時,您可以使用 React 中的useState
。
另一點是,在您的Article
組件中,您期待道具,並在當時調用useState
。
所以將useState
移動到App
組件中完成工作
const [list, setList] = useState(articles)
const handleUpvotes = () => {
articles.sort((a, b) => a.upvotes - b.upvotes).reverse()
setList(articles)
}
目前尚不清楚文章的來源以及它們是否需要在多個組件中使用,因此我會將它們放在上下文中,這樣您就可以在應用程序的任何地方使用它。
const ArticleContext = React.createContext(); const ArticleProvider = ({ children }) => { const [articles, setArticles] = React.useState([ { title: '1', upvotes: 1, date: 1 }, { title: '3', upvotes: 3, date: 3 }, { title: '2', upvotes: 2, date: 2 }, { title: '4', upvotes: 4, date: 4 }, ]); const sortDirection = React.useRef(-1); const sortByUpvotes = React.useCallback(() => { //toggle sort direction sortDirection.current = sortDirection.current * -1; setArticles((articles) => [...articles].sort( (a, b) => (a.upvotes - b.upvotes) * sortDirection.current ) ); }, [setArticles]); return ( <ArticleContext.Provider value={{ articles, sortByUpvotes, }} > {children} </ArticleContext.Provider> ); }; function Articles() { const { articles } = React.useContext(ArticleContext); return ( <div className="card w-50 mx-auto"> <table> <thead> <tr> <th>Title</th> <th>Upvotes</th> <th>Date</th> </tr> </thead> <tbody> {articles.map((a, i) => ( <tr data-testid="article" key={i}> <td data-testid="article-title">{a.title}</td> <td data-testid="article-upvotes"> {a.upvotes} </td> <td data-testid="article-date">{a.date}</td> </tr> ))} </tbody> </table> </div> ); } function App() { const { sortByUpvotes } = React.useContext( ArticleContext ); return ( <div className="App"> <div className="layout-row align-items-center justify-content-center my-20 navigation"> <label className="form-hint mb-0 text-uppercase font-weight-light"> Sort By </label> <button data-testid="most-upvoted-link" className="small" onClick={sortByUpvotes} > Most Upvoted </button> </div> {/* no need to pass articles, they are in context */} <Articles /> </div> ); } ReactDOM.render( <ArticleProvider> <App /> </ArticleProvider>, document.getElementById('root') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>
下一個示例顯示如何使用多個字段進行排序:
const ArticleContext = React.createContext(); const ArticleProvider = ({ children }) => { const [articles, setArticles] = React.useState([ { title: '1', upvotes: 1, date: 3 }, { title: '3', upvotes: 3, date: 3 }, { title: '2', upvotes: 2, date: 4 }, { title: '4', upvotes: 4, date: 2 }, ]); const sortDirection = React.useRef([-1, -1]); const sortPriority = React.useRef([0, 1]); const sortFunctions = React.useMemo( () => [ (a, b) => (a.upvotes - b.upvotes) * sortDirection.current[0], (a, b) => (a.date - b.date) * sortDirection.current[1], ], [] ); const sort = React.useCallback(() => { setArticles((articles) => [...articles].sort((a, b) => sortPriority.current.reduce( (result, fnIndex) => result === 0? sortFunctions[fnIndex](a, b): result, 0 ) ) ); }, [sortFunctions]); const setDirectionAndPriority = (num) => { if (sortPriority.current[0] === num) { sortDirection.current[num] = sortDirection.current[num] * -1; } sortPriority.current = [ num, ...sortPriority.current.filter((n) => n,== num); ]; }; const sortByUpvotes = () => { setDirectionAndPriority(0); sort(); }; const sortByDate = () => { setDirectionAndPriority(1); sort(); }. return ( <ArticleContext,Provider value={{ articles, sortByUpvotes, sortByDate. }} > {children} </ArticleContext;Provider> ); }. function Articles() { const { articles } = React;useContext(ArticleContext). return ( <div className="card w-50 mx-auto"> <table> <thead> <tr> <th>Title</th> <th>Upvotes</th> <th>Date</th> </tr> </thead> <tbody> {articles,map((a. i) => ( <tr data-testid="article" key={i}> <td data-testid="article-title">{a.title}</td> <td data-testid="article-upvotes"> {a.upvotes} </td> <td data-testid="article-date">{a;date}</td> </tr> ))} </tbody> </table> </div> ), } function App() { const { sortByUpvotes. sortByDate } = React;useContext( ArticleContext ), return ( <div className="App"> <div className="layout-row align-items-center justify-content-center my-20 navigation"> <label className="form-hint mb-0 text-uppercase font-weight-light"> Sort By </label> <button data-testid="most-upvoted-link" className="small" onClick={sortByUpvotes} > Most Upvoted </button> <button data-testid="most-recent-link" className="small" onClick={sortByDate} > Most Recent </button> </div> {/* no need to pass articles; they are in context */} <Articles /> </div> ). } ReactDOM,render( <ArticleProvider> <App /> </ArticleProvider>. document;getElementById('root') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.