[英]How do I update the state of a child component?
so I have two buttons in my react App.js and when clicked I want my current state(list) to change to descending order according to which button i press(order by date or order by upvotes).所以我在我的 React App.js 中有两个按钮,单击时我希望我的当前状态(列表)根据我按下的按钮(按日期排序或按投票排序)更改为降序。 My articles.js have the code that display the list of articles.
我的 articles.js 有显示文章列表的代码。 But I'm having a hard time showing the list sorted after clicking the button tag found on my App.js which is the parent component.
但是我很难显示在单击父组件 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;
The useState
should be in the 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)
}
You should use the Effect Hook ( https://reactjs.org/docs/hooks-effect.html ).您应该使用 Effect Hook ( https://reactjs.org/docs/hooks-effect.html )。
useEffect(() => {
// articles was changed
}, [articles])
the problem that you are facing is that a misunderstanding of the React reactivity model, now lets take a look at this line您面临的问题是对 React 反应性 model 的误解,现在让我们看看这一行
articles.sort((a, b) => a.upvotes - b.upvotes).reverse()
here you are successfully updating the array, but think about it.在这里,您已成功更新数组,但请考虑一下。 if React updated the UI whenever a variables inside the component updates that would be ineffective and problematic.
如果 React 在组件内的变量更新时更新 UI,那将是无效和有问题的。
so in order to notify React about what has changed and it needs to update the UI, whenever you change a variable and you need the UI to update, you use useState
from react.因此,为了通知 React 发生了什么变化并且它需要更新 UI,每当您更改变量并且需要更新 UI 时,您可以使用 React 中的
useState
。
and another point is that in your Article
component you are expecting props, and calling useState
at the time.另一点是,在您的
Article
组件中,您期待道具,并在当时调用useState
。
so moving the useState
into the App
component dose the work所以将
useState
移动到App
组件中完成工作
const [list, setList] = useState(articles)
const handleUpvotes = () => {
articles.sort((a, b) => a.upvotes - b.upvotes).reverse()
setList(articles)
}
It is not clear where articles come from and if they need to be used in multiple components so I'll put them in context, that way you can use it anywhere in your application.目前尚不清楚文章的来源以及它们是否需要在多个组件中使用,因此我会将它们放在上下文中,这样您就可以在应用程序的任何地方使用它。
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>
The next example shows how to sort using multiple fields:下一个示例显示如何使用多个字段进行排序:
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.