首页 > 解决方案 > React JS - 将静态数组对象从 DBJSON 切换为对象

问题描述

我在下面有这个脚本可以成功运行。此外,您可以在此链接中看到此脚本正在运行:https ://codepen.io/claudio-bitar/pen/VERORW但我更改了一些不起作用的内容,您可以在下面的前面的解释中看到

class TodoApp extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: {            
        "elements": ['a','b','c','d','e','f','g','h','i','j','k']          
  },

      currentPage: 1,
      todosPerPage: 3
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(event) {
    this.setState({
      currentPage: Number(event.target.id)
    });
  }

  render() {
    const { todos, currentPage, todosPerPage } = this.state;

    // Logic for displaying current todos
    const indexOfLastTodo = currentPage * todosPerPage;
    const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
    const currentTodos = todos.elements.slice(indexOfFirstTodo, indexOfLastTodo);

    const renderTodos = currentTodos.map((todo, index) => {
      return <li key={index}>{todo}</li>;
    });

    // Logic for displaying page numbers
    const pageNumbers = [];
    for (let i = 1; i <= Math.ceil(todos.elements.length / todosPerPage); i++) {
      pageNumbers.push(i);
    }

    const renderPageNumbers = pageNumbers.map(number => {
      return (
        <li
          key={number}
          id={number}
          onClick={this.handleClick}
        >
          {number}
        </li>
      );
    });

    return (
      <div>
        <ul>
          {renderTodos}
        </ul>
        <ul id="page-numbers">
          {renderPageNumbers}
        </ul>
      </div>
    );
  }
}


ReactDOM.render(
  <TodoApp />,
  document.getElementById('app')
);

所以,我想做同样的事情,但使用来自 DBJson 的对象替换 todos 的数组。因此,我在下面的代码中进行了更改,但没有成功。出现了这个错误信息:

TypeError:无法读取未定义的属性“切片”

import React, { Component } from 'react'
import axios from 'axios'

const URL_TODOS = 'http://localhost:3001/todos';

    class Todos extends Component {
      constructor(props) {
        super(props);
        this.state = {    
          todos: [],        
          currentPage: 1,
          todosPerPage: 3
        };
        this.handleClick = this.handleClick.bind(this);
      }

      handleClick(event) {
        this.setState({
          currentPage: Number(event.target.id)
        });
      }



      componentDidMount() {
        axios.get(URL_TODOS)
          .then(res => {
            this.setState({ todos: res.data })
          })       
      }



      render() {
        const { todos, currentPage, todosPerPage } = this.state;

        // Logic for displaying current todos
        const indexOfLastTodo = currentPage * todosPerPage;
        const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
        const currentTodos = todos.elements.slice(indexOfFirstTodo, indexOfLastTodo); 


        const renderTodos = currentTodos.map((todo, index) => {
          return <li key={index}>{todo}</li>;
        });

        // Logic for displaying page numbers
        const pageNumbers = [];
        for (let i = 1; i <= Math.ceil(todos.elements.length / todosPerPage); i++) {
          pageNumbers.push(i);
        }

        const renderPageNumbers = pageNumbers.map(number => {
          return (
            <li
              key={number}
              id={number}
              onClick={this.handleClick}
            >
              {number}
            </li>
          );
        });

        return (
          <div>
            <ul>
              {renderTodos}
            </ul>
            <ul id="page-numbers">
              {renderPageNumbers}
            </ul>
          </div>
        );
      }
    }


    export default Todos 

这是我的DBJson文件:

 "todos": [
    {
      "elements": [
        "a",
        "b",
        "c",
        "d",
        "e",
        "f",
        "g",
        "h",
        "i",
        "j",
        "k"
      ]
    }
  ]

我也接受建议如何更轻松地做到这一点。也许改变json结构?我不知道。

标签: javascriptreactjs

解决方案


根据您的 DBJson 文件,您似乎正在接收一个带有对象的数组和一个数组:

"todos": [
  {
    "elements": [
      "a",
      "b",
      "c",
      "d",
      "e",
      "f",
      "g",
      "h",
      "i",
      "j",
      "k"
    ]
  }
]

因此,获取 todos 的第一个元素:

todos[0]

使用异步/等待

在使用 Axios 时,我总是尝试使用 async await,如下所示:

async componentDidMount() {
  try {
    let res = await axios.get(URL_TODOS);
    let response = await res.data;
    this.setState({ todos: response.todos[0] });
  } catch(error) {
    console.error(error);
  }
}

在设置数据之前,您必须等待承诺解决。

然后,从该对象中获取元素。

const { todos, currentPage, todosPerPage } = this.state;
// Logic for displaying current todos
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
const currentTodos = todos.elements.slice(indexOfFirstTodo, indexOfLastTodo);

没有异步/等待

如果您不想使用异步/等待:

componentDidMount() {
  axios.get(URL_TODOS)
    .then(response => response.data)
    .then(data => {
      this.setState({ todos: data[0] })
    })
    .catch(error => { console.error(error) });
}

axios 中的更多信息和示例

这个答案中,我添加了一些关于 fetch 和 axios 的信息和差异,如果你没有得到正确类型的响应,有一些关于使用 axios 的代码可能会对你有所帮助。看看它是否也有帮助。

为什么使用 componentDidMount

来自官方文档

componentDidMount() 在组件安装后立即调用(插入到树中)。需要 DOM 节点的初始化应该放在这里。如果您需要从远程端点加载数据,这是实例化网络请求的好地方。

此方法是设置任何订阅的好地方。如果你这样做了,不要忘记在 componentWillUnmount() 中取消订阅。

您可以立即在 componentDidMount() 中调用 setState()。它会触发额外的渲染,但会在浏览器更新屏幕之前发生。这保证了即使在这种情况下 render() 将被调用两次,用户也不会看到中间状态。请谨慎使用此模式,因为它通常会导致性能问题。在大多数情况下,您应该能够在 constructor() 中分配初始状态。但是,对于模态和工具提示等情况,当您需要在渲染取决于其大小或位置的内容之前测量 DOM 节点时,它可能是必要的。

为什么不使用 componentWillMount

来自官方文档

UNSAFE_componentWillMount() 在挂载之前被调用。它在 render() 之前调用,因此在该方法中同步调用 setState() 不会触发额外的渲染。通常,我们建议使用 constructor() 来代替初始化状态。

避免在此方法中引入任何副作用或订阅。对于这些用例,请改用 componentDidMount()。


推荐阅读