【问题标题】:Passing useState using createContext in React.tsx在 React.tsx 中使用 createContext 传递 useState
【发布时间】:2021-04-23 15:49:29
【问题描述】:

我已经定义了一个上下文Transaction,它接受一个对象和一个函数。 在 AppProvider 中返回 Transaction.Provider。 代码是 GlobalState.tsx 文件:

import { createContext, useState } from "react";

export interface IProviderProps {
    children?: any;
}

type Cat = {
    id: number;
    text: string;
    amount: number;
}

type Ca =Cat[]
export const initialState = {
    state: [
        {id:4, text:'hi', amount:234},
        {id:3, text:'hd', amount:-234},
        {id:1, text:'hs', amount:34}
    ],
    setState: (state: Ca) => {}
}
console.log(initialState.state)
export const Transaction = createContext(initialState);

export const AppProvider = (props: IProviderProps) => {
    const [state, setState] = useState(initialState.state);
    console.log(state);
    return <Transaction.Provider value={{state, setState}}>{props.children}</Transaction.Provider>;
  };

在 App.tsx 中我通过了 Provider:

import React, { useState } from 'react';
import './App.css';
import { Header } from "./Components/Header";
import { Balance } from './Components/Balance';
import { IncomeExpense } from "./Components/Income_Expense";
import { TransactionHistory } from "./Components/TransactionHistory";
import { AddTransaction } from "./Components/AddTransaction";
import { AppProvider } from './Context/GlobalState'

function App() {

  const [islit, setlit] = useState(true);
  

  return (
    <AppProvider>
      <div className={`${islit? '': 'dark'} body`}>
        <Header islit={islit} setlit={setlit} />
        <div className="container">
          <Balance />
          <IncomeExpense />
          <TransactionHistory />
          <AddTransaction />
        </div>
      </div>
    </AppProvider>
  );
}

export default App;

我正在尝试使用“setState”更改“状态”,但它不起作用:

import React, { useState, useContext } from 'react';
import { Transaction} from '../Context/GlobalState';

export const AddTransaction = () => {

  const initialState = useContext(Transaction);
  const [Incexp, setIncExp] = useState('income');
  const [text, settext] = useState('');
  const [amount, setamount] = useState(0);
  const transactions = initialState.state;
  const settransaction = initialState.setState;

  function Addition(e: any) {
    e.preventDefault();
    settext('');
    setamount(0);
    transactions.push({id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount})
    settransaction(transactions);
    console.log(transactions);
  }

  return (
    <div>
      <h3>Add Transaction</h3>
      <form onSubmit={Addition}>
        <label htmlFor="description">Text</label>
        <input type="text" id="description" placeholder="Enter description..." value={text} onChange={(e) => { settext(e.target.value) }} required />

        <label htmlFor="amount">Amount</label>
        <input type="number" id="amount" placeholder="Enter Amount..." value={amount === 0 ? '' : amount} onChange={(e) => { setamount(parseInt(e.target.value)) }} required />
        <div className="Inc-Exp">
          <div>
            <input type="radio" id="income" name="balance" defaultChecked onClick={()=>{setIncExp('income')}}/>
            <label htmlFor="income" className="inc-col">Income</label>
          </div>
          <div>
            <input type="radio" id="expense" name="balance" onClick={()=>{setIncExp('expense')}}/>
            <label htmlFor="expense" className="exp-col">Expense</label>
          </div>
        </div>
        <input className="btn" type="submit" value="Addtransaction" />
      </form>
    </div>
  )
}

另一个子组件:

import React, { useContext } from 'react';
import { Transaction } from '../Context/GlobalState';

export const Balance = () => {

    const initialState = useContext(Transaction);
    const transactions = initialState.state;
    var total=0;
    transactions.map((transaction) => total+=transaction.amount)

    return (
        <div>
            <h4>Your Balance</h4>
            <h1 className={`${total > 0 ? 'plus' : ''} ${total < 0 ? 'minus' : ''}`}>${total}</h1>
        </div>
    )
}

每次我点击一个按钮添加交易。我希望它更新状态。但它没有更新。

【问题讨论】:

  • 据我了解,您将setState 声明为获取输入值的函数,但是当您调用它时,您似乎并未将其用作函数。预期类似:initialState.setState(value_here)。请解释你想做什么,出了什么问题,你得到了什么错误
  • 每次我点击一个按钮添加交易。我希望它更新状态。但它没有更新。
  • 您遇到什么错误?抛出错误?
  • 没有错误是我打错了。

标签: javascript reactjs typescript error-handling


【解决方案1】:

状态未更新,因为您没有更改对象事务的引用,如下所示

  function Addition(e: any) {
    e.preventDefault();
    settext('');
    setamount(0);
    settransaction([...transactions,{id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount} ]);
    console.log(transactions);
  }

在这种情况下,您传递给 settransaction 的对象将有一个新的引用,react 将更新状态

【讨论】:

    【解决方案2】:

    请将setState 更改为回调变体setState((previousState) =&gt; {...}) 为:

    function Addition(e: any) {
        e.preventDefault();
        settext('');
        setamount(0);
        transactions.push({id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount})
        settransaction(transactions);
        console.log(transactions);
      }
    

    到

    function Addition(e: any) {
        e.preventDefault();
        settext('');
        setamount(0);
        settransaction((prevState) => {
    return prevState.push({id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount});
        });
      }
    

    console.log 可能不会显示更新的值,因为需要重新渲染才能获得更新的context 值。

    但是在context 更新之后,react 会触发重新渲染,因此负责显示更新的component 最终会显示更新的状态。

    【讨论】:

    • 我试过这个,但它给了我一个错误。 '(prevState: any) => any' 类型的参数不能分配给 'Ca' 类型的参数。类型“(prevState:any)=> any”缺少类型“Cat []”中的以下属性:pop、push、concat、join 和 27 more.ts(2345)参数“prevState”隐含一个“any”类型。如果我更改 prevState: any 和文件 GlobalState.tsx (我提到的第一个文件)如果我设置 setState: (state: any) => {} console.log 给我一个数字而不是对象数组
    猜你喜欢
    • 2020-11-14
    • 2022-01-23
    • 1970-01-01
    • 2021-04-30
    • 2020-06-27
    • 1970-01-01
    • 2020-03-25
    • 2019-10-20
    • 1970-01-01
    相关资源
    最近更新 更多