Javascript 它赢了';t在状态更改时重新加载子组件
我正在实现fitness tracker,在呈现子组件时遇到问题,这取决于索引 单击按钮后,训练组件将显示选定索引上的对象,但不会重新渲染。我尝试添加日志,日志中的值正在更改,但它只是没有重新渲染。任何建议都将不胜感激 我的主要功能是Javascript 它赢了';t在状态更改时重新加载子组件,javascript,reactjs,babeljs,Javascript,Reactjs,Babeljs,我正在实现fitness tracker,在呈现子组件时遇到问题,这取决于索引 单击按钮后,训练组件将显示选定索引上的对象,但不会重新渲染。我尝试添加日志,日志中的值正在更改,但它只是没有重新渲染。任何建议都将不胜感激 我的主要功能是 import React, { useState } from "react"; import Workout from "./Workout"; import sampleData from "./sampleData"; export default fun
import React, { useState } from "react";
import Workout from "./Workout";
import sampleData from "./sampleData";
export default function App() {
const [exerciseIndex, setExerciseIndex] = useState(0);
const [renderWorkout, setRenderWorkout] = useState([
sampleData[exerciseIndex]
]);
const handleClick = currentIndex => {
//console.log(currentIndex);
setExerciseIndex(currentIndex);
setRenderWorkout(sampleData[exerciseIndex]);
};
const navVal = sampleData.map((exercise, index) => {
return (
<button key={index} onClick={() => handleClick(index)}>
{exercise.date}
</button>
);
});
return (
<div className="App">
<h1>Workouts</h1>
<br />
{navVal}
<Workout initialValues={renderWorkout[exerciseIndex]} />
</div>
);
}
训练部分
import React, { useReducer } from "react";
import "./styles.css";
import update from "react-addons-update";
/*const initialValues = {
...sampleData,
newExerciseName: ""
};*/
export default function Workout(props) {
let newData;
function reducer(state, action) {
switch (action.type) {
case "topTextChange":
return {
...state,
[action.payload.name]: action.payload.value
};
case "addSet":
newData = update(state.workout, {
[action.payload - 1]: {
sets: {
$push: [
{
setId: state.workout[action.payload - 1].sets.length + 1,
weight: 0,
reps: 0
}
]
}
}
});
return {
...state,
workout: newData
};
case "removeSet":
newData = update(state.workout, {
[action.payload - 1]: {
sets: {
$splice: [[state.workout[action.payload - 1].sets.length - 1, 1]]
}
}
});
return {
...state,
workout: newData
};
case "addExercise":
console.log(state);
newData = update(state.workout, {
$push: [
{
exerciseId: state.workout.length + 1,
exerciseName: state.newExerciseName,
sets: []
}
]
});
return {
...state,
workout: newData
};
case "deleteExercise":
const position = state.workout.findIndex(
exercise => exercise.exerciseId === action.payload
);
newData = update(state.workout, {
$splice: [[position, 1]]
});
return {
...state,
workout: newData
};
default:
throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, props.data);
const addExercise = () => dispatch({ type: "addExercise" });
const deleteExercise = id =>
dispatch({ type: "deleteExercise", payload: id });
const changeText = e =>
dispatch({ type: "topTextChange", payload: e.target });
const renderedExercise = state.workout.map((exercise, index) => {
console.log(exercise);
return <Exercise key={index} exercise={exercise} />;
});
function Set(props) {
// ToDo: hook up below values to states
return (
<div>
<label>
{" "}
Weight <input type="text" value={props.weight} />{" "}
</label>
<label>
{" "}
Reps <input type="text" value={props.rep} />{" "}
</label>
</div>
);
}
function Exercise(props) {
const renderedSet = props.exercise.sets.map((set, index) => (
<Set key={index} weight={set.weight} rep={set.reps} />
));
const addSet = id => dispatch({ type: "addSet", payload: id });
const deleteSet = id => dispatch({ type: "removeSet", payload: id });
return (
<div>
{props.exercise.exerciseName}
<button onClick={() => deleteExercise(props.exercise.exerciseId)}>
{" "}
Remove Exercise{" "}
</button>
<button onClick={() => addSet(props.exercise.exerciseId)}>
{" "}
Add Set{" "}
</button>
<button onClick={() => deleteSet(props.exercise.exerciseId)}>
Remove Set
</button>
{renderedSet}
</div>
);
}
return (
<div className="Workout">
{renderedExercise}
<br />
<br />
<input
type="text"
name="newExerciseName"
value={state.newExerciseName}
placeholder="What exercise do you want to add?"
onChange={e => changeText(e)}
/>{" "}
<button onClick={() => addExercise()}>Add Exercise</button>
</div>
);
}
import React,{useReducer}来自“React”;
导入“/styles.css”;
从“react插件更新”导入更新;
/*常量初始值={
…采样数据,
newExerciseName:“
};*/
导出默认功能训练(道具){
让新数据;
功能减速机(状态、动作){
开关(动作类型){
案例“topTextChange”:
返回{
……国家,
[action.payload.name]:action.payload.value
};
案例“addSet”:
newData=更新(state.workout{
[action.payload-1]:{
设置:{
$push:[
{
setId:state.workout[action.payload-1].sets.length+1,
重量:0,,
销售代表:0
}
]
}
}
});
返回{
……国家,
训练:新数据
};
案例“removeSet”:
newData=更新(state.workout{
[action.payload-1]:{
设置:{
$splice:[[state.workout[action.payload-1].sets.length-1,1]]
}
}
});
返回{
……国家,
训练:新数据
};
案例“addExercise”:
console.log(状态);
newData=更新(state.workout{
$push:[
{
exerciseId:state.workout.length+1,
exerciseName:state.newExerciseName,
集合:[]
}
]
});
返回{
……国家,
训练:新数据
};
案例“删除练习”:
const position=state.workout.findIndex(
exercise=>exercise.exerciseId==action.payload
);
newData=更新(state.workout{
$splice:[[位置,1]]
});
返回{
……国家,
训练:新数据
};
违约:
抛出新错误();
}
}
const[state,dispatch]=useReducer(reducer,props.data);
const addExercise=()=>dispatch({type:“addExercise”});
const deleteExecution=id=>
分派({type:“deleteExecution”,有效负载:id});
const changeText=e=>
分派({type:“topTextChange”,有效负载:e.target});
const renderedExercise=state.workout.map((练习,索引)=>{
控制台日志(练习);
返回;
});
功能集(道具){
//ToDo:将以下值连接到状态
返回(
{" "}
权重{'}
{" "}
代表{“}
);
}
功能练习(道具){
const renderedSet=props.exercise.sets.map((集合,索引)=>(
));
const addSet=id=>dispatch({type:“addSet”,payload:id});
constdeleteset=id=>dispatch({type:“removeSet”,payload:id});
返回(
{props.exercise.exerciseName}
deleteExercise(props.exercise.exerciseId)}>
{" "}
删除练习{“”}
addSet(props.exercise.exerciseId)}>
{" "}
添加集{“”}
deleteSet(props.exercise.exerciseId)}>
移除集
{renderedSet}
);
}
返回(
{renderedExercise}
changeText(e)}
/>{" "}
addExercise()}>添加练习
);
}
谢谢,
杰克我找到了解决办法。问题是因为我在子组件“训练”中有状态,并且我没有更新它,因为它已从父组件“应用”更改。我使用forwardRef、useRef和UseImperialiveHandle从父组件更新状态。现在它正在按预期工作。有关更新的实施,请参见下文。有关这些钩子的更多信息,请查看官方的ReactJS指南或是我找到解决方案的地方 App.js
import React, { useState, useRef } from "react";
import Workout from "./Workout";
import sampleData from "./sampleData";
export default function App() {
const workoutRef = useRef(null);
const navVal = sampleData.map((exercise, index) => {
return (
<button key={index} onClick={() => handleClick(index)}>
{exercise.date}
</button>
);
});
const handleClick = currentIndex => {
workoutRef.current.updateExercise(sampleData[currentIndex]);
};
return (
<div className="App">
<h1>Workouts</h1>
<br />
{navVal}
<Workout ref={workoutRef} data={sampleData[0]} />
</div>
);
}
import React,{useState,useRef}来自“React”;
从“/Workout”导入训练;
从“/sampleData”导入sampleData;
导出默认函数App(){
const workoutRef=useRef(null);
const navVal=sampleData.map((练习,索引)=>{
返回(
handleClick(索引)}>
{练习日期}
);
});
const handleClick=currentIndex=>{
workutref.current.updateExercise(sampleData[currentIndex]);
};
返回(
运动
{navVal}
);
}
Workout.js
import React, { useReducer, forwardRef, useImperativeHandle } from "react";
import "./styles.css";
import update from "react-addons-update";
const Workout = forwardRef((props, ref) => {
let newData;
function reducer(state, action) {
switch (action.type) {
case "topTextChange":
return {
...state,
[action.payload.name]: action.payload.value
};
case "addSet":
newData = update(state.workout, {
[action.payload - 1]: {
sets: {
$push: [
{
setId: state.workout[action.payload - 1].sets.length + 1,
weight: 0,
reps: 0
}
]
}
}
});
return {
...state,
workout: newData
};
case "removeSet":
newData = update(state.workout, {
[action.payload - 1]: {
sets: {
$splice: [[state.workout[action.payload - 1].sets.length - 1, 1]]
}
}
});
return {
...state,
workout: newData
};
case "addExercise":
console.log(state);
newData = update(state.workout, {
$push: [
{
exerciseId: state.workout.length + 1,
exerciseName: state.newExerciseName,
sets: []
}
]
});
return {
...state,
workout: newData
};
case "deleteExercise":
const position = state.workout.findIndex(
exercise => exercise.exerciseId === action.payload
);
newData = update(state.workout, {
$splice: [[position, 1]]
});
return {
...state,
workout: newData
};
case "replaceExercise":
return {
...action.payload
};
default:
throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, props.data);
const addExercise = () => dispatch({ type: "addExercise" });
const deleteExercise = id =>
dispatch({ type: "deleteExercise", payload: id });
const changeText = e =>
dispatch({ type: "topTextChange", payload: e.target });
const renderedExercise = state.workout.map((exercise, index) => {
return <Exercise key={index} exercise={exercise} />;
});
const updateExercise = data => {
dispatch({ type: "replaceExercise", payload: data });
};
useImperativeHandle(ref, () => {
return {
updateExercise: updateExercise
};
});
function Set(props) {
// ToDo: hook up below values to states
return (
<div>
<label>
{" "}
Weight <input type="text" value={props.weight} />{" "}
</label>
<label>
{" "}
Reps <input type="text" value={props.rep} />{" "}
</label>
</div>
);
}
function Exercise(props) {
const renderedSet = props.exercise.sets.map((set, index) => (
<Set key={index} weight={set.weight} rep={set.reps} />
));
const addSet = id => dispatch({ type: "addSet", payload: id });
const deleteSet = id => dispatch({ type: "removeSet", payload: id });
return (
<div>
{props.exercise.exerciseName}
<button onClick={() => deleteExercise(props.exercise.exerciseId)}>
{" "}
Remove Exercise{" "}
</button>
<button onClick={() => addSet(props.exercise.exerciseId)}>
{" "}
Add Set{" "}
</button>
<button onClick={() => deleteSet(props.exercise.exerciseId)}>
Remove Set
</button>
{renderedSet}
</div>
);
}
return (
<div className="Workout">
{renderedExercise}
<br />
<br />
<input
type="text"
name="newExerciseName"
value={state.newExerciseName}
placeholder="What exercise do you want to add?"
onChange={e => changeText(e)}
/>{" "}
<button onClick={() => addExercise()}>Add Exercise</button>
</div>
);
});
export default Workout;
import React,{useReducer,forwardRef,useImperialiveHandle}来自“React”;
导入“/styles.css”;
从“react插件更新”导入更新;
常量训练=前进参考((道具,参考)=>{
让新数据;
功能减速机(状态、动作){
开关(动作类型){
案例“topTextChange”:
返回{
……国家,
[action.payload.name]:action.payload.value
};
案例“addSet”:
newData=更新(state.workout{
[action.payload-1]:{
设置:{
$push:[
{
setId:state.workout[action.payload-1].sets.length+1,
重量:0,,
销售代表:0
}
]
}
}
});
返回{
……国家,
训练:新数据
};
案例“removeSet”:
newData=更新(state.workout{
[action.payload-1]:{
设置:{
$splice:[[state.workout[action.payload-1].sets.length-1,1]]
}
}
});
返回{
……国家,
训练:新数据
};
C
import React, { useReducer, forwardRef, useImperativeHandle } from "react";
import "./styles.css";
import update from "react-addons-update";
const Workout = forwardRef((props, ref) => {
let newData;
function reducer(state, action) {
switch (action.type) {
case "topTextChange":
return {
...state,
[action.payload.name]: action.payload.value
};
case "addSet":
newData = update(state.workout, {
[action.payload - 1]: {
sets: {
$push: [
{
setId: state.workout[action.payload - 1].sets.length + 1,
weight: 0,
reps: 0
}
]
}
}
});
return {
...state,
workout: newData
};
case "removeSet":
newData = update(state.workout, {
[action.payload - 1]: {
sets: {
$splice: [[state.workout[action.payload - 1].sets.length - 1, 1]]
}
}
});
return {
...state,
workout: newData
};
case "addExercise":
console.log(state);
newData = update(state.workout, {
$push: [
{
exerciseId: state.workout.length + 1,
exerciseName: state.newExerciseName,
sets: []
}
]
});
return {
...state,
workout: newData
};
case "deleteExercise":
const position = state.workout.findIndex(
exercise => exercise.exerciseId === action.payload
);
newData = update(state.workout, {
$splice: [[position, 1]]
});
return {
...state,
workout: newData
};
case "replaceExercise":
return {
...action.payload
};
default:
throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, props.data);
const addExercise = () => dispatch({ type: "addExercise" });
const deleteExercise = id =>
dispatch({ type: "deleteExercise", payload: id });
const changeText = e =>
dispatch({ type: "topTextChange", payload: e.target });
const renderedExercise = state.workout.map((exercise, index) => {
return <Exercise key={index} exercise={exercise} />;
});
const updateExercise = data => {
dispatch({ type: "replaceExercise", payload: data });
};
useImperativeHandle(ref, () => {
return {
updateExercise: updateExercise
};
});
function Set(props) {
// ToDo: hook up below values to states
return (
<div>
<label>
{" "}
Weight <input type="text" value={props.weight} />{" "}
</label>
<label>
{" "}
Reps <input type="text" value={props.rep} />{" "}
</label>
</div>
);
}
function Exercise(props) {
const renderedSet = props.exercise.sets.map((set, index) => (
<Set key={index} weight={set.weight} rep={set.reps} />
));
const addSet = id => dispatch({ type: "addSet", payload: id });
const deleteSet = id => dispatch({ type: "removeSet", payload: id });
return (
<div>
{props.exercise.exerciseName}
<button onClick={() => deleteExercise(props.exercise.exerciseId)}>
{" "}
Remove Exercise{" "}
</button>
<button onClick={() => addSet(props.exercise.exerciseId)}>
{" "}
Add Set{" "}
</button>
<button onClick={() => deleteSet(props.exercise.exerciseId)}>
Remove Set
</button>
{renderedSet}
</div>
);
}
return (
<div className="Workout">
{renderedExercise}
<br />
<br />
<input
type="text"
name="newExerciseName"
value={state.newExerciseName}
placeholder="What exercise do you want to add?"
onChange={e => changeText(e)}
/>{" "}
<button onClick={() => addExercise()}>Add Exercise</button>
</div>
);
});
export default Workout;