Home > OS >  Button Function Not calling From Another file in React
Button Function Not calling From Another file in React

Time:02-27

I need to call CutomerDashboard.js file's "toggleIsTrucated" function and "isTruncated" to CustomerNotice.js files button onClick and text change places, How can I call that?

(In this customer dashboard file I'm creating a Read function to show some extent of notice text)

import React, {useState,useEffect} from 'react';
import { Input, Row, Col, Button } from 'antd';
import {fetchDashboardMetrics} from "./DashboardApi";
import {items} from "./DashboardItems";
import axios from 'axios';
import CustomerNotice from "./CustomerNotice";

function Read ({children}) {

    const text = children;

    const [isTruncated, setIsTrucated] = useState(true); 

    const result = isTruncated ? text.slice(0,90) : text;

    function toggleIsTrucated(){
        setIsTrucated(!isTruncated);
     }

    return (
        <div>
            {result}....
        </div>
        
    );

}


const CustomerDashboard = () => {

    const [features, setFeatures] = useState(items);
    const source = axios.CancelToken.source()
    const [notice, setNotice] = useState(<Read>Customer Notice: Optimism Is Invaluable For The Meaningful Life. With A Firm Belief In A Positive Future You Can Throw Yourself Into The Service Of That Which Is Larger Than You Are.  -Martin Seligman-</Read>);
    const [noticeVisibility, setNoticeVisibility] = useState(true);
    
    useEffect(() => {
        fetchDashboardMetrics(features, setFeatures,source.token)
        return (() => {
            source.cancel();
        })
    }, []);

    return (
        <>
            <div className='md:pl-8 sm:pl-0'>
                <div className='my-5 '>
                    <p className='mb-8'>My Account - Dashboard Overview</p>
                    {noticeVisibility && <CustomerNotice notice={notice} setNoticeVisibility={setNoticeVisibility}/>}
                </div>
                <ul role="list" className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
                    {features.map((feature) => (
                        <li key={feature.name} className="col-span-1 bg-white rounded-lg shadow divide-y divide-gray-200 relative">
                            <div className="w-full flex items-center justify-between p-6 space-x-6">
                                <div className="flex-1 truncate">
                                    <div className="flex items-center space-x-3 justify-between">
                                        <h3 className="text-gray-900 text-lg truncate">{feature.name}</h3>
                                        {feature.isNew && (
                                            <div className="absolute -top-2 -right-2 p-1 px-4 text-white text-sm bg-red-500">
                                                New
                                            </div>
                                        )}
                                    </div>
                                </div>
                            </div>
                            <div>
                                <div className={'mx-4 mt-2 mb-3 '}>
                                    {feature.details.map((singleDetail) => {
                                        return (
                                            <div className={'flex justify-between text-base'}>
                                                <span>{singleDetail.name}</span>
                                                <span>{singleDetail.value}</span>
                                            </div>
                                        )
                                    })}
                                </div>
                            </div>
                        </li>
                    ))}
                </ul>
            </div>
        </>
    )
}
export default CustomerDashboard;



import React, {useState,useEffect} from 'react';
import {XIcon} from "@heroicons/react/solid";

const CustomerNotice = ({notice, setNoticeVisibility}) => {
    return (
        <div>
            <div className="mt-8 pb-2 sm:pb-5">
                <div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
                    <div className="p-2 rounded-lg bg-orange-600 shadow-lg sm:p-3">
                        <div className="flex items-center justify-between flex-wrap">
                            <div className="w-0 flex-1 flex items-center">
                                <p className="ml-3 font-medium text-white truncate">
                                    <span className="md:inline">{notice}</span>
                                </p>
                            </div>
                            <div className="order-3 mt-2 flex-shrink-0 w-full sm:order-2 sm:mt-0 sm:w-auto">
                                <a
                                    href="#"
                                className="flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-orange-600 bg-white hover:bg-orange-50"
                                >
                                    <button onClick={toggleIsTrucated}>{isTruncated ? "Read More" : "Read Less"}</button>
                                </a>
                            </div>
                            <div className="order-2 flex-shrink-0 sm:order-3 sm:ml-2">
                                <button
                                    onClick={() => setNoticeVisibility(false)}
                                    type="button"
                                    className="-mr-1 flex p-2 rounded-md hover:bg-orange-500 focus:outline-none focus:ring-2 focus:ring-white"
                                >
                                    <span className="sr-only">Dismiss</span>
                                    <XIcon className="h-6 w-6 text-white" aria-hidden="true"/>
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default CustomerNotice;

If this is not possible please suggest me a possible way.

CodePudding user response:

Instead of doing a bunch of hacks, I would recommend simplifying the structure of your components.

import { useState } from 'react'

export default function CustomerDashboard() {
  // I am not sure why you want to keep notice in state,
  // because in your example you did not call setNotice
  const [notice, setNotice] = useState(`
    Customer Notice: Optimism Is Invaluable For The Meaningful Life.
    With A Firm Belief In A Positive Future You Can Throw Yourself Into The Service
    Of That Which Is Larger Than You Are. -Martin Seligman
  `)
  const [isNoticeVisible, setIsNoticeVisible] = useState(true)

  return (
    <div>
      <h1>My Account - Dashboard Overview</h1>

      {isNoticeVisible && (
        <CustomerNotice
          notice={notice}
          setIsNoticeVisible={setIsNoticeVisible}
        />
      )}
    </div>
  )
}

function CustomerNotice(props) {
  const { notice, setIsNoticeVisible } = props
  const [isTruncated, setIsTruncated] = useState(true)

  function toggleIsTruncated() {
    setIsTruncated(!isTruncated)
  }

  return (
    <div>
      <Read text={notice} isTruncated={isTruncated} />

      <button onClick={toggleIsTruncated}>
        {isTruncated ? 'Read More' : 'Read Less'}
      </button>

      <button onClick={() => setIsNoticeVisible(false)}>Dismiss</button>
    </div>
  )
}

function Read(props) {
  const { text, isTruncated } = props
  const result = isTruncated ? text.slice(0, 90) : text

  return <div>{result}....</div>
}

List of the things that were bad in your code.

  1. Keeping the component instance in the state. It is hard to manage. Even your simple case proves that.
  2. Keeping the toggleIsTruncated function inside the Read component. I think we should keep it outside and pass only 2 props to the Read component. I enable exposed only two things
const { text, isTruncated } = props

As you can see it is easy to maintain and allow us to do whatever we want.

PS. If my review and example were helpful please leave the thumbs up.

CodePudding user response:

You can use useImperativeHandle to expose methods or values within Read component to outside.

  1. Update your Read component to expose the methods and values you need. And use forwarded ref to bind them.
const Read = forwardRef(({ children }, ref) => {
  const text = children;

  const [isTruncated, setIsTrucated] = useState(true);

  useImperativeHandle(
    ref,
    () => ({
      toggleIsTrucated: () => {
        setIsTrucated((prev) => !prev);
      },
      isTruncated: isTruncated
    }),
    [isTruncated]
  );

  const result = isTruncated ? text.slice(0, 90) : text;

  return <div>{result}....</div>;
});
  1. In CustomerDashboard create a new ref using useRef and pass it as the ref argument to the Read component you created.
 const readRef = useRef(null);
  const [notice, setNotice] = useState(
    <Read ref={readRef}>
      Customer Notice: Optimism Is Invaluable For The Meaningful Life. With A
      Firm Belief In A Positive Future You Can Throw Yourself Into The Service
      Of That Which Is Larger Than You Are. -Martin Seligman-
    </Read>
  );
  1. In CustomerDashboardNow, you can pass readRef to CustomerNotice as a prop.
           <CustomerNotice
              ...
              ...
              readRef={readRef}
            />
  1. Now in the CustomerNotice component, readRef has current value got assigned the exposed functions and values. Do the null checking and use them.
const CustomerNotice = ({
  ...
  ...
  readRef
}) => {
  return (
      ...
      ...
                 <button
                    onClick={() =>
                      readRef.current && readRef.current.toggleIsTrucated()
                    }
                  >
                    {readRef.current && readRef.current.isTruncated
                      ? "Read More"
                      : "Read Less"}
                  </button>
    ...
    ...
   )
}

Edit unruffled-elbakyan-pizsot

  • Related