Home > Net >  How to display the desired information on click ReactJS
How to display the desired information on click ReactJS

Time:08-17

My page is divided into right and left parts. On the left side there are 3 buttons, and on the right side there is a list with 3 texts. They are in different files. I want the corresponding text to come first in the list when the button is clicked. The functionality is similar to tabs, but I don’t know how to implement it, because the components are in different files and are not connected. How can I do that?

//Buttons.js

const btnArr = [
["Togle Text 1"],
["Togle Text 2"],
["Togle Text 3"],
];

const Buttons = () => {
  return (
    <div style={{ width: "50%" }}>
        {btn.map((btn, index) => (
          <Button
            key={index}
            text={btn}
          />
      ))}
  );
};

//Text.js

const btnArr = [
["Text 1"],
["Text 2"],
["Text 3"],
];

const Texts = () => {
  return (
    <div style={{ width: "50%" }}>
        {texts.map((txt, index) => (
          <Text
            key={index}
            text={txt}
          />
      ))}
  );
};

CodePudding user response:

Parent Component

You'll want to use a useState in a parent component of both Texts and Buttons. That way you can keep track of which button has been clicked, and you'll pass Buttons a way to update which has been clicked. You'll also be able to pass Texts the value of which text is currently selected.

That parent component could look like this:

  const [selectedText, setSelectedText] = useState(0);
  return (
    <div
    >
      <Buttons onSelect={setSelectedText} />
      <Texts selectedText={selectedText} />
    </div>
  );

Buttons Component

Next we'll handle the Buttons Component. You can see in the above codeblock we are passing Buttons a prop called onSelect which we'll use to update the selectedText state.

Here's what that component could look like:

export const Buttons = ({ onSelect }) => {
  return (
    <div>
      {btnArr.map((btn, index) => (
        <Button key={index} text={btn} onClick={() => onSelect(index)} />
      ))}
    </div>
  );
};

Now, whenever a button is clicked, the selectedText state variable in the Parent will be updated to the index of the button clicked.

Texts Component

The Texts Component is a little bit trickier because we need to show the selected Text before the other Texts.

Since we are passing in selectedText as a prop, we can use that as we are creating the list. Our Texts component should look like this:

export const Texts = ({ selectedText }) => {

The most basic way to order the list is by placing our selectedText item first, followed by the mapped over text elements, but with the selectedText item filtered out. It may make more sense to look at the code:

{<Text text={texts[selectedText]} />}
{texts
  .filter((txt, index) => index !== selectedText)
  .map((txt, index) => (
    <Text key={index} text={txt} />
  ))}

That way will work just fine, but if you don't want to have a <Text ... /> in two places, we can avoid that by using the following code instead. The more complicated way to do this is by using sort: we can sort through the text array to order them and then map over them like this:

{texts
  .sort((txt, txt2) =>
    txt === texts[selectedText]
      ? -1
      : txt2 === texts[selectedText]
      ? 1
      : 0
  )
  .map((txt, index) => (
    <Text key={index} text={txt} />
  ))}

I've put together a full example of this on CodeSandbox here: Edit amazing-bird-el1vdh

Extending the List

The advantage of doing it this way is that you can easily add more items to the list of buttons/text. If we simply add a ["Toggle Text 4"] to the button list and a ["Text 4"] to the text list, you can see that everything still just works.

The CodePen example demonstrates this.

Working with Different Files

In my explanation, we worked with three separate files for our code: a parent file, Texts.js, and Buttons.js.

Here's how you can use the Texts and Buttons component from inside the parent:

In the parent file at the top, import the other two files like this:

import { Texts } from "./Texts";
import { Buttons } from "./Buttons";

Then inside Texts.js, make sure to have the word export before the component is defined like this:

export const Texts = ({ selectedText }) => {

Do the same in Buttons.js:

export const Buttons = ({ onSelect }) => {

This allows us to use code from one file in a separate file. This guide gives a bit more explanation on how that works.

CodePudding user response:

You can figure out that by Lifting State Up. You can try this but this isn't the best practice you can try make to order with id.

Buttons.js

const btnArr = [["Togle Text 1"], ["Togle Text 2"], ["Togle Text 3"]];

const Buttons = (props) => {
  return (
    <div style={{ width: "50%" }}>
      {btnArr.map((btn, index) => (
        <button key={index} onClick={() => props.onButtonClick(index)}>
          {btn}
        </button>
      ))}
    </div>
  );
};

export default Buttons;

Texts.js

const textArr = [["Text 1"], ["Text 2"], ["Text 3"]];

const Texts = (props) => {
  return (
    <div style={{ width: "50%" }}>
      {<p>{textArr[props.order]}</p>}
      {textArr.map((txt, index) => {
        return index != props.order ? <p key={index}>{txt}</p> : null;
      })}
    </div>
  );
};

export default Texts;

App.js

import { useState } from "react";
import Buttons from "./Buttons";
import Texts from "./Text";
function App() {
  const [textIndex, setTextIndex] = useState(0);
  function onButtonClick(buttonIndex) {
    console.log(buttonIndex);
    setTextIndex(buttonIndex);
  }
  return (
    <>
      <Buttons onButtonClick={onButtonClick} />
      <Texts order={textIndex} />
    </>
  );
}

export default App;

Notice: I change the Component and the Component to facilitate the example

CodePudding user response:

My advice would be to look into React-Redux. This is a state-management system that exists "outside" your component structure in a store. This allows non-related components to speak to each other.

Another option, though less clean would be to send the information from one component to the first parent that contains both components through callbacks, then pass the information through props to the other child component.

EDIT: Redux may be too complex, and too much effort depending on the complexity of the project. Passing through callbacks and props should be enough.

  • Related