onClick function for array of buttons not working - javascript

Here the List get's 'n' values from the app.component. I am trying to write onclick function for each of the buttton. Here, is the code
onChildButtonClick = (val) => {
console.log(val);}
function makeButton(data) {
return (
<button onClick = {this.onChildButtonClick.bind(null, data.name)} >
{data.name} </button>
);}
const List = (props) => {
const {projectnames} = props
return (
<tr>
<div> {
projectnames.map(makeButton, this)
}
</div>
</tr>
)
}
When I try to execute it throws me an error onChildButtonClick is not defined.

As your code stands above, you're referencing this.onChildButtonClick which is looking within the scope of the function. But your function onChildButtonClick is outside of that scope.
Edit:
I haven't had a chance to test it, but try this out:
function makeButton(data) {
const onChildButtonClick = (val) => {
console.log(val);
}
return (
<button onClick = {onChildButtonClick.bind(this, data.name)} >
{data.name} </button>
);
}
const List = (props) => {
const {projectnames} = props
return (
<tr>
<div> {
projectnames.map(makeButton, this)
}
</div>
</tr>
)
}

Related

React calling component function outside of the component

I have a functional component:
function Tile(props: any) {
const selectTile = (() => {
...
})
return (
<div>
...
</div>
)
}
I then create another functional component which will hold many tiles.
function Grid(props: any) {
const selectAllTiles = (() => {
})
return (
<div>
<Tile></Tile>
<Tile></Tile>
<Tile></Tile>
</div>
)
}
My question is, how can I call the selectTile() function for each Tile within the selectAllTiles() function? What approaches are there?
I would make the parent component keep track of selected tiles, and it will then inform each Tile (through props) if it is selected or not.
If a Tile should be able to "make itself selected", then a function can be passed from the parent into each Tile (also through props) that the Tile can call and which will update the selected tiles collection in the parent.
Updated code:
function Tile(props: any) {
const { isSelected, makeSelected } = props;
return (
<div style={{ ... something based on isSelected ... }}>
<button type="button" onClick={makeSelected}>Select me</button>
</div>
)
}
function Grid(props: any) {
const [isSelected, setIsSelected] = useState<bool[]>([false, false, false]);
const makeSelected = (index: int) => {
// ...
setIsSelected(...);
}
return (
<div>
<Tile isSelected={isSelected[0]} makeSelected={() => makeSelected(0)}></Tile>
<Tile isSelected={isSelected[1]} makeSelected={() => makeSelected(1)}></Tile>
<Tile isSelected={isSelected[2]} makeSelected={() => makeSelected(2)}></Tile>
</div>
)
}
This is just an (untested) example, many approaches are possible.
why don't use like this:
function Tile(props: any) {
return (
<div>
...
</div>
)
}
const selectTile = (() => {
...
})

How to pass HTML attributes to child component in React?

I have a parent and a child component, child component has a button, which I'd like to disable it after the first click. This answer works for me in child component. However the function executed on click now exists in parent component, how could I pass the attribute down to the child component? I tried the following and it didn't work.
Parent:
const Home = () => {
let btnRef = useRef();
const handleBtnClick = () => {
if (btnRef.current) {
btnRef.current.setAttribute("disabled", "disabled");
}
}
return (
<>
<Card btnRef={btnRef} handleBtnClick={handleBtnClick} />
</>
)
}
Child:
const Card = ({btnRef, handleBtnClick}) => {
return (
<div>
<button ref={btnRef} onClick={handleBtnClick}>Click me</button>
</div>
)
}
In general, refs should be used only as a last resort in React. React is declarative by nature, so instead of the parent "making" the child disabled (which is what you are doing with the ref) it should just "say" that the child should be disabled (example below):
const Home = () => {
const [isButtonDisabled, setIsButtonDisabled] = useState(false)
const handleButtonClick = () => {
setIsButtonDisabled(true)
}
return (
<>
<Card isDisabled={isButtonDisabled} onButtonClick={handleButtonClick} />
</>
)
}
const Card = ({isDisabled, onButtonClick}) => {
return (
<div>
<button disabled={isDisabled} onClick={onButtonClick}>Click me</button>
</div>
)
}
Actually it works if you fix the typo in prop of Card component. Just rename hadnlBtnClick to handleBtnClick
You don't need to mention each prop/attribute by name as you can use javascript Object Destructuring here.
const Home = () => {
const [isButtonDisabled, setIsButtonDisabled] = useState(false)
const handleButtonClick = () => {
setIsButtonDisabled(true)
}
return (
<>
<Card isDisabled={isButtonDisabled} onButtonClick={handleButtonClick} />
</>
)
}
const Card = (props) => {
return (
<div>
<button {...props}>Click me</button>
</div>
)
}
You can also select a few props and use them differently in the child components. for example, see the text prop below.
const Home = () => {
const [isButtonDisabled, setIsButtonDisabled] = useState(false)
const handleButtonClick = () => {
setIsButtonDisabled(true)
}
return (
<>
<Card text="I'm a Card" isDisabled={isButtonDisabled} onButtonClick={handleButtonClick} />
</>
)
}
const Card = ({text, ...restProps}) => {
return (
<div>
<button {...restProps}>{text}</button>
</div>
)
}

How to pass variable in a function call?

In my functional component I'm calling two functions, which are doing nearly the same thing:
const App = () => {
const handleOnClickFirst = () => {
setValue('first')
}
const handleOnClickSecond = () => {
setValue('second')
}
return (
<div>
{anything === true
? <Button onClick={handleOnClickFirst} />
: <Button onClick={handleOnClickSecond} />}
</div>
)
}
So there should be simply only
const handleOnClick = (value) => {
setValue(value)
}
But how do I pass the value in onClick?
As we know with JSX you pass a function as the event handler. So we can wrap our handler with another function and call handler with arguments in this wrapper function
onClick={(event) => handleOnClick(value)}
or for old versions we can do
onClick={function(event){ handleOnClick(value) }}
If you don't need events you can just pass it like this
onClick={() => handleOnClick(value)}
Also if it is a Class base component we use bind to pass method context and arguments
class App extends React.Component {
handleOnClick(val) {
console.log(`${val}`);
}
render() {
return (
<button onClick={this.handleOnClick.bind(this, "test")}>
click me
</button>
);
}
}
You could do
onClick={() => handleOnClick(value)}
edit:
More information here: https://reactjs.org/docs/faq-functions.html
You can do this :
<button onClick={(event)=>handleOnClick(<pass your paramter here>)}></button>
Try this:
const App = () => {
const handleOnClick = (passedInValue) => {
setValue(passedInValue)
}
return (
<div>
{anything === true
? <Button onClick={() => handleOnClick("first")} />
: <Button onClick={() => handleOnClick("second")} />}
</div>
)
}

Passing down function from parent to child through React functional component

I am trying to pass down the functions setDir and handleSort() down from SearchAppointments (parent) to Hooks(child), but I keep getting errors saying that they are not functions.
I tried to debug it by looking the typeof handleSort in the useEffecthook of the child component, though it console.logged two statements: 1) underfined 2) function. Not sure what is wrong.
const SearchAppointments = React.memo(() => {
const [orderDir, setDir] = useState("");
const handleSort = (e) => {
let value = e.target.value;
setDir(value);
let order;
let filterData = data;
if (orderDir === 'asc') {
order = 1;
} else {
order = -1;
}
};
return (
<>
<div>
<Hooks handleSort={handleSort} setDir={setDir} />
</div>
</>
);
});
const Hooks = React.memo(({ handleSort, setDir }) => {
useEffect(() => {
console.log(typeof handleSort);
}, []);
return (
<div>
<div>
<button type="button" onClick={() => setDir("success")}>
Set Dir
</button>
<button type="button" value='asc' onClick={handleSort}>
Handle Sort (Asc)
</button>
<button type="button" value='dsc' onClick={handleSort}>
Handle Sort (Dsc)
</button>
</div>
</div>
);
});
try and use memo like this:
const comparator = (previous, next) => {
if (something) {
return true
}
return false
}
const Hooks = React.memo(({ handleSort, setDir }) => {
useEffect(() => {
console.log(typeof handleSort);
}, []);
return (
<div>
<div>
<button type="button" onClick={() => setDir("success")}>
Set Dir
</button>
<button type="button" value='asc' onClick={handleSort}>
Handle Sort (Asc)
</button>
<button type="button" value='dsc' onClick={handleSort}>
Handle Sort (Dsc)
</button>
</div>
</div>
);
}, comparator);
define a function and pass that as the second argument. memo function (I've called it comparator, then returns true or false depending on when you want the component to update. think of it as the new shouldComponentUpdate in the lifecycle methods. but use with care as your application might not update if you use carelessly

React, handle modal from component

How can I catch the click on some buttom from a modal, to return true or false to the component that is calling the modal?
handleSubmitSaveConfigurations = async (row) => {
const { scadaValidation } = this.props;
const result = await scadaValidation(11);
if (result.statusCode !== 200) {
// Opens the modal to ask if you really want to save
this.setState({openSimpleModal: true});
this.setState({contentSimpleModal: this.warningModal()});
// Here I have to catch if the modal click yes or no.
// In case yes, do nothing and continue with the code
// But in case "no" returns false and stops
}
// If result.statusCode === 200 returns true
return true;
}
warningModal = () => (
<div>
Do you want to save?
<Button id="btnClose" onClick={() => this.handleModalClickClose()}>No</Button>
<Button id="btnSave" onClick={() => this.handleModalClickClose()}>Yes</Button>
</div>
);
handleModalClickClose = () => this.setState({ openSimpleModal: false });
You could pass a handler to be executed inside your modal.
const Modal = ({ callback }) =>{
const handleClick = arg => callback(arg)
return(
<div>
<button onClick={() => handleClick('button1')}>A</button>
<button onClick={() => handleClick('button2')}> B</button>
</div>
)
}
And expect to receive this value inside the component which is calling Modal
const TheOneWhoCalls = () =>{
const onModalClick = arg => console.log(arg)
return <Modal callback={onModalClick} />
}
You can create a function on the parent component, and inside the modal, u only use it.
https://reactjs.org/docs/lifting-state-up.html#lifting-state-up
Parent:
constructor () {
this.state: {test: false}
}
setStateTest (value) {
this.setState(value)
}
render () {
return <modal handlerSetParentStateTest = {setStateTest}></modal>
}
Modal:
// this will set the parent state
this.props.handlerSetParentStateTest(true);
I want to share my solution, for sure I will need it in the future. it the implementation of #Dupocas
const Modal = ({ callback }) => {
const handleClick = arg => callback(arg)
return (
<div>
Wanna save?
<Button id="btnCloseModal" onClick={() => handleClick(0)}>No</Button>
<Button id="btnGuardarConfirm" onClick={() => handleClick(1)}>Sí</Button>
</div>)
};
class TableDisplayReportRecord extends Component<Props, State> {
constructor {...}
handleValidate = async (row) => {
const { scadaValidation } = this.props;
const verify = await scadaValidation();
if (verify.statusCode !== 200) {
this.setState({openSimpleModal: true});
const onModalClick = arg => {
this.setState({openSimpleModal: false});
//do nothing
if (arg === 0) return false;
//if user selected "Yes", call the function that I need
else this.handleSubmitSave(row);
};
this.setState({contentSimpleModal:
<Modal
callback={onModalClick}
/>
})
}
}
handleSubmitSave = async (row) => {...}
...
}

Categories

Resources