Search code examples
react-nativewebviewdropdown

Passing values between dropdown list and webview components in React native


I'm developing an app with snack.expo.dev. In a form i have two components: a dropdown list and a webview. When i select an url in dropdown list, the webview shows his web page. This is DROPDOWNLIST.JS:

import React, { useState } from 'react';
  import { StyleSheet, Text, View, Alert } from 'react-native';
  import { Dropdown } from 'react-native-element-dropdown';
  import AntDesign from '@expo/vector-icons/AntDesign';
  import DropDownPicker from 'react-native-dropdown-picker';

  
  const data = [
    { label: 'Python', value: 'https://python.org' },
    { label: 'Java', value: '   https://microsoft.com' },
    { label: 'Swift', value: 'https://swift.org' },
    { label: 'Kotlin', value: 'https://kotlinlang.org' },
    
  ];
  
  const DropdownComponent = () => {
    const [value, setValue] = useState(null);
    const [isFocus, setIsFocus] = useState(false);
    const [url, setUrl] = useState('');
    const renderLabel = () => {
      if (value || isFocus) {
        return (
          <Text style={[styles.label, isFocus && { color: 'blue' }]}>
            
          </Text>
        );
      }
      return null;
    };

    return (
      <View style={styles.container}>
       
        <Dropdown
          style={[styles.dropdown, isFocus && { borderColor: 'blue' }]}
          placeholderStyle={styles.placeholderStyle}
          selectedTextStyle={styles.selectedTextStyle}
          inputSearchStyle={styles.inputSearchStyle}
          iconStyle={styles.iconStyle}
          data={data}
          search
          maxHeight={'100%'}
          
          labelField="label"
          valueField="value"
          placeholder={!isFocus ? 'Select item' : ''}
          searchPlaceholder="Search..."
          value={value}
          onFocus={() => setIsFocus(true)}
          onBlur={() => setIsFocus(false)}
           onChange={item => {
            setValue(item.value);
            setIsFocus(false);
            Alert.alert(item.value)
          }}
          
        />
      </View>
    );
  };

  export default DropdownComponent;
  

  const styles = StyleSheet.create({
    container: {
      backgroundColor: 'white',
      padding: 2,
    },
    dropdown: {
      height: 40,
      borderColor: 'gray',
      borderWidth: 0.5,
      borderRadius: 8,
      paddingHorizontal: 8,
      width:'100%',
    },
    icon: {
      marginRight: 5,
    },
    label: {
      position: 'absolute',
      backgroundColor: 'white',
      left: 22,
      top: 8,
      zIndex: 999,
      paddingHorizontal: 8,
      fontSize: 14,
    },
    placeholderStyle: {
      fontSize: 16,
    },
    selectedTextStyle: {
      fontSize: 16,
    },
    iconStyle: {
      width: 20,
      height: 20,
    },
    inputSearchStyle: {
      height: 40,
      fontSize: 16,
    },
  });

This is WEBVIEWER.JS:

import React, { Component } from 'react';
import { StyleSheet, Text, View, Alert } from 'react-native';
import { WebView } from 'react-native-webview';
import mainUrl from './DropdownList'

// ...
export default function WebViewer() {
  return <WebView source={{ uri: mainUrl }} style={{ width:'100%' }} />;
}

This is MAINFORM.JS that calls the components above:

import React, { Component } from 'react';
import { Text, View, StyleSheet, Image, Dimensions, StatusBar } from 'react-native';

import ToolBar from './ToolBar';
import WebViewer from './WebViewer'

const Header =()=> {
  return (
    <View style={styles.header}>
      <ToolBar/>  
    </View>
  )
}
const Box =()=> {
  return (
    <View style={styles.box}>
      <WebViewer/>
    </View>
  )
}

export default function MainForm() {
  return (
   <View style={styles.container}> 
    <Header/>
    <Box/>
    </View>
  );
}

const styles = StyleSheet.create({
  
  container: {
    flex:1,
  },

  header: {
    width:'100%',
    height:54,
  },

  box: {
    width:'100%',
    height:'100%',
    }
  
});

MainForm is parent of both dropdown list and webview components. How can i pass the url from dropdownlist to webview? Some ideas?

EDIT: Ok, I try to do myself following: useContext.

I want to use Context: in MainForm

const Context = createContext(null);

function MainForm() {
   const [url, setUrl] = useState(null);
  return (
   
    <Context.Provider value= {url}>
   <View style={stylesForm.container}> 
    <Header/>
    <Box/>
    </View>
   </Context.Provider>
  )
}

const Header =()=> {
  return (
    <View style={stylesForm.header}>
      <ToolBar/>  
    </View>
  )
}

const Box =()=> {
  return (
    <View style={stylesForm.box}>
      <WebViewer/>
    </View>
  )
}

then in DropDownlist:

const DropdownList= () => {

    const myUrl = useContext(Context);
    
    const [value, setValue] = useState(null);
    const [isFocus, setIsFocus] = useState(false);
    //const [url, setUrl] = useState('');
    const renderLabel = () => {
      if (value || isFocus) {
        return (
          <Text style={[styles.label, isFocus && { color: 'blue' }]}>
          </Text>
        );
      }
      return null;
    };
    return (
      <View style={styles.container}>
        <Dropdown
          style={[stylesDropdown.dropdown, isFocus && { borderColor: 'blue' }]}
          placeholderStyle={stylesDropdown.placeholderStyle}
          selectedTextStyle={stylesDropdown.selectedTextStyle}
          inputSearchStyle={stylesDropdown.inputSearchStyle}
          iconStyle={stylesDropdown.iconStyle}
          data={data}
          search
          maxHeight={'100%'}
          labelField="label"
          valueField="value"
          placeholder={!isFocus ? 'Select item' : ''}
          searchPlaceholder="Search..."
          value={value}
          onFocus={() => setIsFocus(true)}
          onBlur={() => setIsFocus(false)}
          onChange={item => {
            setValue(item.value);
            setIsFocus(false);
            
            myUrl.setUrl(item.value);
            Alert.alert(url);
          }}
        />
      </View>
    );
  };

MainForm embed both ToolBar and Webviewer and Toolbar embed DropdownList. In the property onChange of Dropdownlist i want display the url with a Alert statement to see if it is right, but when i run, it display an error message "Cannot read property 'setUrl' of null"

Why? What i'm wrong? Help me please.


Solution

  • Ok i solve by following way:

    1. i add a new component UrlContext in UrlProvider.js:

    import React, { createContext, useContext, useState, useEffect } from 'react';
    
    const Context = createContext();
    const UrlContext = (props) => {
        const [url, setUrl]= useState('');
        return (
            <Context.Provider value={{url, setUrl}}>
                {props.children}
            </Context.Provider>
        );
    }
    
    export {Context, UrlContext }

    1. in App.js:

    export default function App() {
      
      return (
        <UrlContext>
          <View style={styles.container}>
            <MainForm />
          </View>
          </UrlContext>
      );
    }

    1. in DropdownList:

     const DropdownList= () => {
        
        const {url, setUrl} = useContext(Context);
    
        return (
        
          <View style={styles.container}>
            <Dropdown
               onChange={item => {
                
                setUrl(item.value);
    
             }}
            />
          </View>
          
        );
      };

    1. in Webview:

    function WebViewer() {
         const {url, setUrl} = useContext(Context);
      
      return <WebView source={{ uri:url}} style={{ width:'100%',backgroundColor:'white', }} />;
    }