只需更改状态对象属性,是否有可能触发ReactJs组件重新渲染?

时间:2020-06-26 20:20:24

标签: reactjs

我正在学习ReactJs,尝试使用useStateuseContext钩子时遇到了一个问题。似乎仅在存在参考更改而不是值更改的情况下才会进行重新渲染。以下面的代码为例:

https://stackblitz.com/edit/react-ts-4gw3h1

class Counter {
   count: number;
   constructor(count: number) {
     this.count = count;
   }
   
   increase() {
     this.count += 1;
   }
}

export const CountComponent : FC = (props) => {
   //const [count, setCount] = useState(0); // work
   //const [count, setCount] = useState({0}); // work
   const [counter] = useState(new Counter(0)); // not work

   const doAdd = () => {
      counter.increase();
      console.log(counter.count);
   }
    
   // this will not actually re-render 
   return (<div>{counter.count}<button onClick={doAdd}>+</button></div>);
}

单击按钮时,计数增加,但是呈现的值未更新。我在那里错过了什么吗?有没有一种方法可以让组件监视状态对象属性的变化?

编辑

我想我已经将人们与这个问题的意图混淆了。考虑一个更复杂的用例,其中我有一个复杂的状态对象。请用伪代码对付我:

class Cargo {
    orders: Map<string, Products[]>;
    totalValue: number;
    totalNumber: number;

    addProduct(product: Product) {
      // ignore the null check here.
      this.orders.get(product.owner).push(product);
      this.totalValue += product.value;
      this.totalNumber ++;
    }
}

class Product {
   owner: string;
   name: string;
   value: number;
}

const CargoContext = createContext(new Cargo());

const CargoContext = createContext({... new Cargo(), setTotalValue, setTotalNumber});

// lost the OO
const {orders, totalValue, totalNumber, setTotalValue, setTotalNumber} = useContext(CargoContext);

const doAdd = (product: Product) => {
   orders.get(product.owner); 
   setTotalValue(product.value);
   setTotalNumber(totalNumber + 1);
}

以这种方式创建上下文时,我将无法实际更新状态。根据我的阅读,使之起作用的唯一方法是解构Cargo对象并传递属性和调度程序。但这会丢失面向对象的CargoaddProduct接口。如何更优雅地处理此案?

1 个答案:

答案 0 :(得分:1)

在处理复杂状态时,最好使用useReducer。跟您的货物示例一样,它会像

interface CargoState {
    orders: Map<string, Products[]>;
    totalValue: number;
    totalNumber: number;
}

const cargoReducer = (state: CargoState, action): CargoState => {
   switch (action.type) {
       case 'add-product': {
           const newOrders = state.orders;
           newOrders.get(action.product.name).push(action.product);

           return {
               ...state,
               orders: newOrders,
               totalValue: state.totalValue + product.value,
               totalNumber: state.totalNumber++,
           }
       }
       default: return state;
    }
}



const [state, dispatch] = useReducer(cargoReducer, [some initial state here]);


dispatch({ type: 'add-product', product });

可以正确键入操作,因此您不会丢失任何键入内容。