首页 > 解决方案 > 如何在 React.. 中创建对象的实例?

问题描述

我对 react 和 javascript 很陌生,但我正在尝试构建一个简单的 ToDo 应用程序。在我想从文件中读取数据并在屏幕上显示该数据之前,这并不复杂。问题是我不知道如何创建一个新的 Todo 对象以将其作为参数传递给 addTodo 函数。谢谢大家,希望你们能帮助我!!

我把代码放在这里(请看-loadFromFile-函数,有问题的地方:

import React, { useState } from 'react';
import TodoForm from './TodoForm';
import Todo from './Todo';
import data from  './data/data.json'


function TodoList() {
  const [todos, setTodos] = useState([]);

  
  const loadFromFile = data.map( ( data) => {
    const newTodo = addTodo(new Todo(data.id,data.text));
    return  ( {newTodo} )});


  const addTodo = todo => {
    if (!todo.text || /^\s*$/.test(todo.text)) {
      return;
    }

    const newTodos = [todo, ...todos];

    setTodos(newTodos);
    console.log(...todos);
  };

  const updateTodo = (todoId, newValue) => {
    if (!newValue.text || /^\s*$/.test(newValue.text)) {
      return;
    }

    setTodos(prev => prev.map(item => (item.id === todoId ? newValue : item)));
  };

  const removeTodo = id => {
    const removedArr = [...todos].filter(todo => todo.id !== id);

    setTodos(removedArr);
  };

  const completeTodo = id => {
    let updatedTodos = todos.map(todo => {
      if (todo.id === id) {
        todo.isComplete = !todo.isComplete;
      }
      return todo;
    });
    setTodos(updatedTodos);
  };

  return (
    <>
      <TodoForm onSubmit={addTodo} />
      {loadFromFile}
      <Todo 
        todos={todos}
        completeTodo={completeTodo}
        removeTodo={removeTodo}
        updateTodo={updateTodo}
      />
    </>
  );
}

export default TodoList;

我想创建 Todo 对象的新实例。我尝试了很多次,许多不同的形式,但仍然不起作用。我有一个来自 data.json 文件的 id 和一个文本。我想用这两个值创建 Todo 对象的实例。但是怎么做?

import React, { useState } from 'react';
import TodoForm from './TodoForm';
import EditIcon from '@material-ui/icons/Edit';
import DeleteIcon from '@material-ui/icons/Delete';


const Todo = ({ todos, completeTodo, removeTodo, updateTodo }) => {
  
  const [edit, setEdit] = useState({
    id: null,
    value: ''
  });

  const submitUpdate = value => {
    updateTodo(edit.id, value);
    setEdit({
      id: null,
      value: ''
    });
  };

  if (edit.id) {
    return <TodoForm edit={edit} onSubmit={submitUpdate} />;
  }

  return todos.map((todo, index) => (
    <div
      className={todo.isComplete ? 'todo-row complete' : 'todo-row'}
      key={index}
    >
      <p> <div key={todo.id} onClick={() => completeTodo(todo.id)}>
        {todo.text}
      </div> 
      </p>

      <div className='icons'>
        <DeleteIcon fontSize="small"
          onClick={() => removeTodo(todo.id)}
          className='delete-icon'
        />
        <EditIcon
          onClick={() => setEdit({ id: todo.id, value: todo.text })}
          className='edit-icon'
        />
      </div>
    </div>
  ));
};

export default Todo;

import React, { useState, useEffect, useRef } from 'react';
import { Fab, IconButton } from "@material-ui/core";
import AddIcon from '@material-ui/icons/Add';

function TodoForm(props) {
  const [input, setInput] = useState(props.edit ? props.edit.value : '');

  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  });

  const handleChange = e => {
    setInput(e.target.value);
  };

  const handleSubmit = e => {
    e.preventDefault();

    props.onSubmit({
      id: Math.floor(Math.random() * 10000),
      text: input
    });
    setInput('');
  };

  return (
    <form onSubmit={handleSubmit} className='todo-form'>
      {props.edit ? (
        <>
          <textarea cols="10"
            placeholder='Update item'
            value={input}
            onChange={handleChange}
            name='text'
            ref={inputRef}
            className='todo-input edit'
          />
          <button onClick={handleSubmit} className='todo-button edit'>
            Save
          </button>
        </>
      ) : (
        <>
          <input
            placeholder='Add item'
            value={input}
            onChange={handleChange}
            name='text'
            className='todo-input'
            ref={inputRef}
          />
          
          <Fab color="primary" aria-label="add"> 
            < AddIcon onClick={handleSubmit} fontSize="small" /> 
          </Fab>
        </>
      )}
    </form>
  );
}

export default TodoForm;

标签: javascriptreactjsreact-nativereact-hooksfrontend

解决方案


问题

啊,我知道你现在得到了什么,你想从外部文件加载一些待办事项列表。我在您的代码中看到的主要问题是您试图Todo手动调用/构造一个 React 组件,而这根本不是 React 的工作方式。您将数据/状态/道具渲染到 JSX 中并将其传递给 React,React 会处理实例化组件并计算渲染的 DOM。

const loadFromFile = data.map((data) => {
  const newTodo = addTodo(new Todo(data.id, data.text));
  return ({newTodo});
});

Todo不应该直接调用,React 会处理这个。

解决方案

由于它看起来已经是一个具有和属性data的对象数组,因此它可以方便地匹配您在 state 中存储的内容。您可以简单地作为初始状态值传递。idtextdatatodos

const [todos, setTodos] = useState(data);

如果数据不容易消耗,您可以创建一个初始化函数来获取data并将其转换/映射到您的代码需要的对象形状。

const initializeState = () => data.map(item => ({
  id: item.itemId,
  text: item.dataPayload,
}));

const [todos, setTodos]= useState(initializeState);

运行示例:

import data from "./data.json";

function TodoList() {
  const [todos, setTodos] = useState(data); // <-- initial state

  const addTodo = (text) => {
    if (!text || /^\s*$/.test(text)) {
      return;
    }

    setTodos((todos) => [todo, ...todos]);
  };

  const updateTodo = (id, newTodo) => {
    if (!newTodo.text || /^\s*$/.test(newTodo.text)) {
      return;
    }

    setTodos((todos) => todos.map((todo) => (todo.id === id ? newTodo : todo)));
  };

  const removeTodo = (id) => {
    setTodos((todos) => todos.filter((todo) => todo.id !== id));
  };

  const completeTodo = (id) => {
    setTodos((todos) =>
      todos.map((todo) =>
        todo.id === id
          ? {
              ...todo,
              isComplete: !todo.isComplete
            }
          : todo
      )
    );
  };

  return (
    <>
      <TodoForm onSubmit={addTodo} />
      <Todo
        todos={todos}
        completeTodo={completeTodo}
        removeTodo={removeTodo}
        updateTodo={updateTodo}
      />
    </>
  );
}

编辑 how-can-i-create-an-instance-of-an-object-in-react


推荐阅读