簡體   English   中英

如何更新子組件的 state?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM