Jason
Jason

Reputation: 732

React useEffect equivalent in class component

I have a React functional component that does the following:

import React, { useEffect, useState } from "react";
import axios from "axios";
import mytable from "./mytable";

const baseRawData = [
  { name: "name", value: "John Doe" },
  { name: "sex", value: "M" }
];

export default function FuncComp() {
  let [rawData, setRawData] = useState(baseRawData);
  let [mappedData, setMappedData] = useState([]);
  let [apiFilter, setApiFilter] = useState("all");

  useEffect(() => {
    setMappedData(
      rawData.map(e => ({
        ...e
        // Some logic
      }))
    );
  }, [rawData]);

  useEffect(() => {
    axios.post(`/my/api/${filter}`).then(({ data }) => {
      setRawData(data);
    });
  }, [apiFilter]);

  return (
    <div>
      <h1>The filter is '{apiFilter}'</h1>
      <mytable data={mappedData} />
      <input
        value={apiFilter}
        onBlur={e => setApiFilter(e.target.value)}
        type="text"
      />
    </div>
  );
}

How would I, in a class component, achieve the same logic as useEffect to map the newly received raw data every time the user changes the filter and new raw data is received?

Upvotes: 9

Views: 32349

Answers (2)

Afia
Afia

Reputation: 683

This solution is based on the following assumptions;

  1. You have a baseData you want to render when the component first render.
  2. Once the component is mounted, you request new data from the api.
  3. If the filter is empty, you make a request without the filter.
  4. Once the filter value is set, you make another request with the filter.

Code

import React, { Component } from "react";
import axios from "axios";
import mytable from "./mytable";

const baseRawData = [
  { name: "name", value: "John Doe" },
  { name: "sex", value: "M" }
];

export default class ClassComp extends Component{
  state = {
    rawData: baseRawData,
    mappedData: [],
    apiFilter: ""
  }

  componentDidMount() {
    axios.post(`/my/api`)
    .then(({ data }) => {
      this.setState({ mappedData : data });
    });
  }

  filterPost = (e) => {
    this.setState({ apiFilter: e.target.value},() => {
      axios.post(`/my/api/${this.state.apiFilter}`)
        .then(({ data }) => {
          this.setState({ mappedData : data });
        });
    });
  }

  render() {
    const {apiFilter, mappedData, baseRawData } = this.state;

  return (
    <div>
      <h1>The filter is '{apiFilter}'</h1>
      <mytable data={ mappedData ? mappedData : baseRawData } />
      <input
        value={apiFilter}
        onBlur={e => this.filterPost(e.target.value)}
        type="text"
      />
    </div>
  );
 }
}

Upvotes: 2

Antonio Giordano
Antonio Giordano

Reputation: 173

Before converting it back to a class component, I would simplify the functional one like this

import React, { useEffect, useState } from "react";
import axios from "axios";
import mytable from "./mytable";

const baseRawData = [
  { name: "name", value: "John Doe" },
  { name: "sex", value: "M" }
];

const mapData = rawData => rawData.map(e => ({
  ...e
  // Some logic
}));

export default function FuncComp() {
  let [mappedData, setMappedData] = useState(mapData(baseRawData));
  let [apiFilter, setApiFilter] = useState("all");

  useEffect(() => {
    axios.post(`/my/api/${apiFilter}`).then(({ data }) => {
      setMappedData(mapData(data));
    });
  }, [apiFilter]);

  return (
    <div>
      <h1>The filter is '{apiFilter}'</h1>
      <mytable data={mappedData} />
      <input
        value={apiFilter}
        onBlur={e => setApiFilter(e.target.value)}
        type="text"
      />
    </div>
  );
}

and then you can convert useState in simple state vars. I didn't run the code but it should be something like this.

import React from "react";
import axios from "axios";
import mytable from "./mytable";

const baseRawData = [
  { name: "name", value: "John Doe" },
  { name: "sex", value: "M" }
];

const mapData = rawData => rawData.map(e => ({
  ...e
  // Some logic
}));

class component extends React.Component {
  constructor() {
    this.state = {
      mappedData: mapData(baseRawData),
      apiFilter: 'all'
    }
  }

  filterChanged(newApiFilter) {
    this.setState({apiFilter: newApiFilter});
    axios.post(`/my/api/${newApiFilter}`).then(({ data }) => {
      this.setState({
        mappedData: mapData(data)
      })
    });
  }

  render () {
    const {apiFilter, mappedData} = this.state;
    return (
      <div>
        <h1>The filter is '{apiFilter}'</h1>
        <mytable data={mappedData} />
        <input
          value={apiFilter}
          onBlur={e => this.filterChanged(e.target.value)}
          type="text"
        />
      </div>
    );
  }
}

Upvotes: 2

Related Questions